Метка: python

  • UnicodeDecodeError: ‘ascii’ codec can’t decode byte 0xc2 in position 0: ordinal not in range(128)

    Капец, это вынос мозга, всегда разрабатывал под ubuntu, а тут приходится в Win это делать, и вылазят такие невероятные ошибки и грабли… вот сегодняшяя….


    ctype = ctype.encode(default_encoding) # omit in 3.x!

    UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 0: ordinal not in range(128)

    сразу же всё предельно и ясно, он нам прямым текстом говорит что надо топать в реестр
    вот сюда
    HKEY_CLASSES_ROOT\MIME\Database\Content Type
    и тут находим в самом низу ветки с русскими символами, и переименовывает в транслит\латиницу.

    аминь…

    оказывается это давний баг, есть решение вот тут
    http://softwaremaniacs.org/forum/django/31707/

    А как вы боретесь с такими глюками?
    чем заменяете cmd чтоб было удобно работать как в привычном terminal ?

  • Django показывать в админке пользователю только его объекты

    Ещё довольно частая задача, надо чтоб пользователю в админке показывались только его объекты.
    и второй момент, есть у нас в модели поле автор

        author = models.ForeignKey(User, null = True, blank = True , verbose_name=u'Имя')Code language: Python (python)

    и хочу чтоб пользователю в админке это поле не показывалось, но автоматически при сохранении подставлялся request.user

    Реализуется это как всё по Джанговски в пару движений

    в admin.py
    наследуемся от модели admin
    и немногожечrо допиливаем её

    class ListAdmin(admin.ModelAdmin):
        # Добавим всякие фильтра
        list_filter = ('rooms','region','street', 'pub_date')
        #Говорим, чтоб не показывать это поле
        exclude = ('author',)
        # Тут начинается магия, СуперАдмину показываем всё, а пользователю, показываем только его объекты
        def queryset(self, request):
            if request.user.is_superuser:
                return super(ListAdmin, self).queryset(request)
            else:
                return super(ListAdmin, self).queryset(request).filter(author = request.user)
        # Так решим вторую задачу, в поле author подставляем request.user
        def save_model(self, request, obj, form, change):
            if getattr(obj, 'author', None) is None:
                obj.author = request.user
            obj.save()
            
    admin.site.register(Estate,ListAdmin)Code language: Python (python)

    Вот и всё, не забываем создать отдельную группу для пользователей, в которой указать ту часть приложений куда они могут обращаться.

  • Django загрузка картинки и создания кропнутой превьюшки ( thumbnail )

    И так господа, продолжаю ковыряться в Django, продолжу тему создания расширенного профиля и создания аватарки разных размеров.

    Напомню, что у нас есть модель профиль и там поле аватарки

     avatar = models.ImageField(verbose_name=u'Путь до аватарки', upload_to = 'users/', null = True, blank = True)Code language: Python (python)

    Теперь предположим, что у нас 2 странички, одна страничка целиком и полностью посвящена Пользователю, например так

    И например вот такая страница где выводится полный список всех пользователей

    разные размеры, разные соотношения сторон, привет верстальщику 😉
    Ну да ладно, блуждая по тырнету наткнулся на сниппет

    На его основе делаю, делаю при сохранении модели создания 2х картинок
    одну звать полностью, у второй есть дописка _thumb.jpg например

    def save(self,size=(276,317), *args, **kwargs):
            super(UserProfile, self).save(*args, **kwargs)
            try:
                # Создаём первое изображение
                filename= self.avatar.path
                image = Image.open(filename)
                image.thumbnail(size, Image.ANTIALIAS)
                image.save(filename)
                #Создаём мелкую картинку, если оно не верных размером кропаем под вёрстку
                size=(104,127)
                pw = self.avatar.width
                ph = self.avatar.height
                nw = size[0]
                nh = size[1]
    
                # only do this if the image needs resizing
                if (pw, ph) != (nw, nh):
                    filename = str(self.avatar.path)
                    image = Image.open(filename)
                    pr = float(pw) / float(ph)
                    nr = float(nw) / float(nh)
    
                    if pr > nr:
                        # photo aspect is wider than destination ratio
                        tw = int(round(nh * pr))
                        image = image.resize((tw, nh), Image.ANTIALIAS)
                        l = int(round(( tw - nw ) / 2.0))
                        image = image.crop((l, 0, l + nw, nh))
                    elif pr < nr:
                        # photo aspect is taller than destination ratio
                        th = int(round(nw / pr))
                        image = image.resize((nw, th), Image.ANTIALIAS)
                        t = int(round(( th - nh ) / 2.0))
                        print((0, t, nw, t + nh))
                        image = image.crop((0, t, nw, t + nh))
                    else:
                        # photo aspect matches the destination ratio
                        image = image.resize(size, Image.ANTIALIAS)
                    file, ext = os.path.splitext(filename)
                    image.save(file + "_thumb.jpg", "JPEG")
            except :
                filename=''Code language: Python (python)

    По итогу создаются 2 картинки, для вывода полного изображения ничего не придумываю просто в шаблоне

    <img src="/media/{{ profile.avatar }}"/>Code language: HTML, XML (xml)

    А для вывода второго изображения описываю свойство дополнительное, примерно вот так

        def avatarTumb(self):
            try:
                filename= self.avatar.path
                file = os.path.basename(filename)
                files, ext = os.path.splitext(file)
                return u'%s_thumb.jpg' % (files)
            except :
                filename=''Code language: Python (python)

    ну и собственно обращаемся вот так

    <img src="/media/users/{{ item.get_profile.avatarTumb }}" />Code language: HTML, XML (xml)

    Свои варианты предлагайте ниже, как показало время это полезно очень, что-то можно сделать более удобно, может где-то я допустил ошибку 😉

  • Расширение профиля пользователя django

    в Django я по прежнему новичок, но что-то стараюсь понять и запомнить.

    стояла задача расширить профиль пользователя дополнительными полями, статей на эту тему пресс и малелькая тележка, но не получалось, то у кого-то на сайте парсер html сильно злой и код надо было переписывать, у кого-то были ошибки в примерах и т.п.

    но как-то оно получилось, попробую собрать все мысли в кучу в эту статью.

    Многие знают о django-registration и вот от автора этого замечательного приложения существует django-profiles котором я и воспользовался.

    устанавливаем django-profiles

    easy_install django-profilesCode language: Bash (bash)

    в models.py создадим модель профиля, которая наследуется от штатной User и добавим в ней нужное нам поле

    from django.contrib.auth.models import User
    ...
    ...
    class UserProfile(models.Model):
        # поле для связки со встроенной моделью пользователя Django
        user = models.ForeignKey(User, unique=True)
        # наше новое поле
        about = models.TextField(blank=True)Code language: Python (python)

    Далее в settings.py надо указать кто будет новым AUTH_PROFILE_MODULE

    AUTH_PROFILE_MODULE = 'list.UserProfile'Code language: Python (python)

    где list это ваше приложение в котором расположена модель расширяющая пользователя

    в принципе на этом можно закончить, ибо обращаться теперь можно к

    {{ user.get_profile.about }}Code language: Bash (bash)

    только нужно обратить внимание что надо пользоваться не context а RequestContext
    и указать это в
    TEMPLATE_CONTEXT_PROCESSORS файла settings.py

    TEMPLATE_CONTEXT_PROCESSORS = (
    	 ...
    	 'django.contrib.auth.context_processors.auth',
    	 ...
    	 ) Code language: Python (python)

    но мы идём дальше

    Теперь нам надо подключить django-profiles для просмотра\редактирования профиля

    в файле urls.py
    подключаем

        ...
        (r'^profiles/', include('profiles.urls')),
        ...Code language: Python (python)

    в settings.py также подключим приложение

    INSTALLED_APPS = (
    	 ...
    	 'profiles',
    	 )Code language: Python (python)

    теперь создадим таблицы в базе

    python manage.py syncdbCode language: Python (python)

    приложение profiles использует вот такие шаблоны

        profiles/create_profile.html
        profiles/edit_profile.html
        profiles/profile_detail.html
        profiles/profile_list.htmlCode language: Bash (bash)

    по названию понятно что к чему

    для начала отредактируем edit_profile.html

    {% extends "base.html" %}
    {% block title %}Edit Profile{% endblock %}
     
    {% block content %}
    <h1>Edit contact info for {{ user }} </h1>
     
    <form method="POST" action="">
        {{ form }}
        <input type="submit" name="submit" value="Update" id="submit">
    </form>
     
    {% endblock content %}Code language: HTML, XML (xml)

    сохраняем, теперь можно обратиться к /profiles/edit/ то должно открыться форма редактирования профиля.

    бывают ситуации, что в профиле есть какие-то поля, что запрещено редактировать пользователю, реализуется это довольно просто

    создаём класс формы, наследуемой от общей формы, в котором перечисляем, то что нам исключить от вывода пользователю
    forms.py

    from django.db import models
    from django.forms import ModelForm
    from PROJ.apps.APP.models import UserProfile
    
    .........
    class ProfileForm(forms.ModelForm):
      class Meta:
          model = UserProfile
          exclude = ('user','last_name',)Code language: Python (python)

    from PROJ.apps.APP.models import UserProfile
    проект и приложение где расположена расширенная модель

    теперь в urls.py надо указать, что страницу редактирования профиля надо открывать с нужной нам формой

    from PROJ.APP.forms import ProfileForm
    ........
        ('^profiles/edit', 'profiles.views.edit_profile', {'form_class': ProfileForm,}),
        (r'^profiles/', include('profiles.urls')),
    .......Code language: Python (python)

    Должно получиться примерно так.. проверяем на странице редактирования профиля (/profiles/edit/).

    Теперь сделаем страницу отображения профиля profile/profile_detail.html

    вывести можно что угодно из профиля вот так

    <p><strong>Address 2:</strong><br>{{ profile.address2 }}</p>Code language: Python (python)

    где address2 это дополнительное поле
    список пользователей с профилями можно вывести вот так

    profiles/profile_list.html

    {% extends "base.html" %}
    {% block content %}
    <h1>Список пользователей</h1>
    <br/><br/>
        {% for p in object_list  %}
    <a href="{% url profiles_profile_detail p.user %}">{{ p.user }}</a>
    {% endfor %}
    {% endblock %}Code language: Python (python)

    Теперь задача такая, сейчас профиль и пользователь живут почти своей жизнью, при регистрации пользователя профиль сам не создаётся это мы сейчас и решим сигналами.

    в models.py добавим

    from django.db.models import signals
    from bucket.signals import create_profile
     
    # When model instance is saved, trigger creation of corresponding profile
    signals.post_save.connect(create_profile, sender=User)Code language: Python (python)

    создадим файл, если он не создан signals.py:

    def create_profile(sender, instance, signal, created, **kwargs):
        """When user is created also create a matching profile."""
    
        from PROJ.apps.APP.models import UserProfile
    
        if created:
            UserProfile(user = instance).save()
            # Do additional stuff here if needed, e.g.
            # create other required related recordsCode language: Python (python)

    вот и всё, при регистрации нового пользователя автоматически будет создаваться к нему профиль, если у вас уже сейчас много пользователей, то создать для каждого профиль можно вот так

    $ python manage.py shell
     
    from django.contrib.auth.models import User
    from bucket.models import Profile
     
    users = User.objects.all()
    for u in users:
         try:
              p = u.get_profile()
         except p.DoesNotExist:
              Profile(user = u).save()Code language: Python (python)

    ещё коснусь вопроса редактирования своего email в профиль, пока ещё не совсем разобрался с этим.

    пока есть только пример, делается это анналогично через forms.py

    class ProfileForm(ModelForm):
     
        def __init__(self, *args, **kwargs):
            super(ProfileForm, self).__init__(*args, **kwargs)
            try:
                self.fields['email'].initial = self.instance.user.email
                # self.fields['first_name'].initial = self.instance.user.first_name
                # self.fields['last_name'].initial = self.instance.user.last_name
            except User.DoesNotExist:
                pass
     
        email = forms.EmailField(label="Primary email",help_text='')
     
        class Meta:
          model = Profile
          exclude = ('user',)        
     
        def save(self, *args, **kwargs):
            """
            Update the primary email address on the related User object as well.
            """
            u = self.instance.user
            u.email = self.cleaned_data['email']
            u.save()
            profile = super(ProfileForm, self).save(*args,**kwargs)
            return profileCode language: Python (python)

    надеюсь вернусь к этому вопросу

  • django + twitter

    «Мопед не мой, я лишь объяву разместил»
    У меня пока не хватает кармы, чтоб высылать за такие статьи инвайты на хабр, поэтому видимо кроме меня этого не жалает делать никто, то буду опубликовать тут. ибо информацию считаю полезной, не только для себя.

    Доброго времени суток!
    Появилась необходимость следующего характера: в движке на django, при публикации новости, чтоб создавался кросс-пост на twitter. Т.е. пишем новость, жмём сохранить и на твиттере появляется пост аля «Название статьи, bit.ly/s/ссылка_на_нашу_новость».

    Для реализации потребовались следующие пакеты:

    1. python-oauth2 | https://github.com/simplegeo/python-oauth2
    2. oauth-python-twitter2 | http://code.google.com/p/oauth-python-twitter2/
    3. simplejson | http://pypi.python.org/pypi/simplejson/
    4. oauth2 | http://pypi.python.org/pypi/oauth2/
    5. bitlyapi | http://pypi.python.org/pypi/bitlyapi/

    1-4 пакеты нужны нам для связи с twitter’ом, 5-ый для укорачивания ссылок…
    Перед тем как начать предполагаю, что у Вас есть аккаунт в twitter.com и bit.ly. Если нет, то это по минуте на регистрацию на каждом из сервисов.

    Начнём с twitter’a…

    При-python-им twitter

    Проставляем все пакеты и выполняем следующие действия (кстати они описаны выше в руководстве python-oauth2):
    Логинимся в браузере в twitter.com, и после этого переходим по ссылке http://twitter.com/apps/new. Далее мы воспользуемся инструкциями из замечательной статьи:

    1. Заполняем все поля на свое усмотрение, для Application Type выбираем Client
    2. Для Default Access type выбираем Read & Write, Use Twitter for login я оставил не выбранным
    3. Вводим капчу и сабмитим

    После этого twitter сгенерит CONSUMER_KEY, CONSUMER_SECRET.
    Следующие два параметра нам вернет такой скрипт

    from oauthtwitter import OAuthApi
    import pprint
    
    CONSUMER_KEY = "*****"
    CONSUMER_SECRET = "*****"
    
    twitter = OAuthApi(consumer_key, consumer_secret)
    temp_credentials = twitter.getRequestToken()
    print(twitter.getAuthorizationURL(temp_credentials))
    oauth_verifier = raw_input('What is the PIN? ')
    access_token = twitter.getAccessToken(temp_credentials, oauth_verifier)
    
    print("oauth_token: " + access_token['oauth_token'])
    print("oauth_token_secret: " + access_token['oauth_token_secret'])Code language: Python (python)

    В CONSUMER_KEY, CONSUMER_SECRET вводим значения полученные на предыдущем этапе, запускаем. Скрипт сгенерит url, переходим по нему и копируем PIN который нам вежливо предлагает twitter. Вставляем PIN в скрипт, он как раз его ждет.

    На выходе мы получим значения для двух последних параметров OAUTH_TOKEN и OAUTH_TOKEN_SECRET.
    Все, теперь у нас есть все что надо для oauth авторизации, осталось немного подправить скрипты.

    Готовимся сокращать ссылки вместе с bit.ly

    Предельно простой и удобный модуль bitlyapi. Схема простая:

    1. Регистрируемся на bit.ly
    2. Логинимся
    3. Переходим по ссылке
    4. Копируем username и api key

    Правим модель в Django

    Здесь мы не рассматриваем создание модели, предполагается, что Вы это умеете. В шапку добавляем:

    #twitter
    import oauth2 as oauth
    import bitlyapi
    bitly = bitlyapi.BitLy('username bitly', 'api key bitly') #вводим данные с прошлого шага
    from oauthtwitter import OAuthApi
    CONSUMER_KEY = "*****вводим свои данные*****"
    CONSUMER_SECRET = "*****вводим свои данные*****"
    OAUTH_TOKEN = "*****вводим свои данные*****"
    OAUTH_TOKEN_SECRET = "*****вводим свои данные*****"
    twitter = OAuthApi(CONSUMER_KEY, CONSUMER_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET)Code language: Python (python)

    Переходим к моделе. Логика проста, есть boolean поле twitter_export, если галочка ставится, то новость публикуется при сохранении на твиттере. Если не понятно, то сейчас всё увидите и поймёте ))

    class News(models.Model):
        title = models.CharField(max_length=300)
        content = models.TextField()
        twitter_export = models.BooleanField(default=False)
    
    def save(self):
        link = bitly.shorten(longUrl='http://example.com/news/' + str(self.id) + '/') #формируем ссылку, которая будет сокращенна
        if self.twitter_export:   #если стоит галочка на twitter_export
            twit = u'%s... | Читать %s' % (self.title[:70], link['url'])  #формируем, что писать в твиттер.. учтите, что длина сообщения в твиттере 160 символов
            twitter.UpdateStatus(twit) #публикуем наш твит
            self.twitter_export = False #убираем галку twitter_export
        super(News, self).save()Code language: Python (python)

    Всё готово! Можно тестировать!

    Источники

    1. Пишем twitter-бота на python
    2. Twitter Three-legged OAuth Example