• Почему при установлении атрибутов width и height в поле модели ImageField выдается ошибка?

    @marazmiki
    Укротитель питонов
    Потому что эти артибуты не задают ширину и высоту рисунка. Они задают названия полей, в которые джанга запишет актуальную ширину и высоту загруженной картинки. Типа того:
    class MyModel(models.Model):
        img_width = models.PositiveIntegerField(null=True)
        img_height = models.PositiveIntegerField(null=True)
        image = models.ImageField(upload_to='photos', height_field='img_height', width_field='img_width', max_length=100)
    Ответ написан
    1 комментарий
  • Как сделать такое же, но используя CBV?

    @marazmiki
    Укротитель питонов
    Комментировать
  • Как сослаться на собственную константу при создании класса?

    @marazmiki
    Укротитель питонов
    class Tag(models.Model):
        TYPE_KEYWORD = '1'
        TYPE_TOPIC = '2'
        
        type = models.IntegerField(default=TYPE_KEYWORD)
    Ответ написан
    Комментировать
  • Почему не создаётся миграция?

    @marazmiki
    Укротитель питонов
    Вангую, что внутри папки приложения нет пакета migrations
    Ответ написан
  • Django как вывести картинки в админке?

    @marazmiki
    Укротитель питонов
    В данном контексте self — это не объект модели, а собственно админка. Вам нужно что-то типа такого:
    def image_img(self, image):
        if image.image:
                return u'< img src="%s" width="100"/>' % image.image.url
            else:
                return '(none)'
        image_img.short_description = 'Thumb'
        image_img.allow_tags = True
    Ответ написан
  • Django: Как открыть сервер разработки для доступа из Интернета?

    @marazmiki
    Укротитель питонов
    Попробуйте запускать ./manage.py runserver 0.0.0.0:8000
    Важный, но не всем очевидный нюанс — для открытия порта ниже 1024 нужны привилегии суперпользователя.
    Ответ написан
    2 комментария
  • Как через pip install -r requirements txt устанавливать только не установленные приложения?

    @marazmiki
    Укротитель питонов
    Вообще говоря, pip так и делает — устанавливает пакет только в том случае, если указанное требование не удовлетворено:
    (.virtualenv) $ pip freeze > requirements.txt
    (.virtualenv) $ pip install -r requirements.txt 
    Requirement already satisfied (use --upgrade to upgrade): Django==1.9 in ./.virtualenv/lib/python3.4/site-packages (from -r requirements.txt (line 2))
    Requirement already satisfied (use --upgrade to upgrade): dj-database-url==0.3.0 in ./.virtualenv/lib/python3.4/site-packages (from -r requirements.txt (line 3))
    Requirement already satisfied (use --upgrade to upgrade): psycopg2==2.6.1 in ./.virtualenv/lib/python3.4/site-packages (from -r requirements.txt (line 4))
    Requirement already satisfied (use --upgrade to upgrade): wheel==0.26.0 in ./.virtualenv/lib/python3.4/site-packages (from -r requirements.txt (line 5))
    Cleaning up...

    Может, у Вас установлена старая версия пакета, например, package-name==0.1, а в requirements.txt указано что-нибудь сложное, типа package-name>=0.3,<0.4? Либо dev-репозиторий, который качается из git?
    Ответ написан
    3 комментария
  • Как пробросить в nginx адрес, на который хочет попасть юзер?

    @marazmiki
    Укротитель питонов
    Нужно правильно настроить nginx, тогда и хост будет определяться как положено. Передавайте из nginx на бэкенд заголовки Host и X-Forwrded-For. И всё будет нормально.

    А что, если не секрет, за специфика такая, из-за которой нельзя пользоваться urls?
    Ответ написан
  • Как наследовать serializer в Django REST Framework?

    @marazmiki
    Укротитель питонов
    # ВОТ ЭТО ДОЛЖНО РАБОТАТЬ, но в validated_data нет files :-(


    Не должно. Обратите внимание на аргумент read_only=True у поля files. Попробуйте угадать, что оно означает, только чур — не подглядывайте в документацию.
    Ответ написан
    2 комментария
  • Как получить значение в классовом представлении?

    @marazmiki
    Укротитель питонов
    Где получить? В шаблоне, в логике вьюхи? Если внутри вьюхи, то в любом методе, включая пресловутый get_context_data(), можно обратиться к объекту через вызов метода get_object():
    def get_context_data(self, **kwargs):
        author = self.get_object()
        kwargs.update(last_accessed=author.last_accessed,
                      name=author.name)
        return super().get_context_data(**kwargs)
    Если речь о шаблоне, то по умолчанию переменная с объектом называется незатейливо — object. Соответственно. в тексте шаблона можно писать
    Hi, {{ object.name }}, you're seen at {{ object.last_accessed }}
    Если не устраивает название object, можно указать имя этой переменной через атрибут context_object_name вашего CBV:
    class AuthorDetail(DetailView):
        context_object_name = 'author'
        model = Author
        template_name = 'author_detail.html'
    и можно будет писать в шаблоне:
    Hi, {{ author.name }}, you're seen at {{ author.last_accessed }}
    Ответ написан
    1 комментарий
  • Есть ли способ объединить TreeForeignKey и ChainedForeignKey?

    @marazmiki
    Укротитель питонов
    Через clean() модели не получится?
    Ответ написан
  • Как заставить django скачать и загрузить картинку?

    @marazmiki
    Укротитель питонов
    Даже если закрыть глаза на оформление кода, постоянное дублирование, то это всё равно очень странный код с неопределённым поведением. И вот почему:
    try:
        categories = Categories.objects.get(name=line[0])    # Метка 1
          img_url = line[1]   # Метка 2
          content = urllib.request.urlopen(img_url).read()        # Метка 3
          Item(categories=categories, img=content, name=line[2], text=line[3], options=line[4]).save()
        except:
          categories = Categories(name=line[0])    # Метка 4
          img_url = line[1]
          content = urllib.request.urlopen(img_url).read()
          Item(categories=categories, img=content, name=line[2], text=line[3], options=line[4]).save()    # Метка 5
    Первым делом хочу обратить внимание на строку с комментарием "Метка 4". Вы, насколько я понял, хотите создать модель Categories, если её не нашлось в строке "Метка 1". Создать-то Вы её создали, но не сохранили! В базе такого объекта нет. Поэтому при вызове сохранения Item (см. "Метка 5") Вы можете схватить ошибку.

    А можете не схватить, потому что возможна другая ситуация, когда категория (см. "Метка 1") нашлась, но картинка для скачивания определилась неправильно, и скачивание сломалось. Или просто сеть недоступна. В этом случае вывалится urllib, а категория будет определена правильно.

    Далее: очень непонятный момент про img=content. Насколько я понял, Вы прямо берёте саму картинку (набор байт) и пишете его в БД? Если да, то это в корне неверно, ImageField работает по-другому. Во-первых, в базе данных это обычный varying charfield. Во-вторых, он хранит не сам контент картинки, а имя файла, под которым файл был сохранён при аплоаде. Сам файл хранится в другом месте (по умолчанию — в файловой системе рядышком в директории, указанной в настройке MEDIA_ROOT) Например, если в таком поле записано значение 'path/to/my/photo.jpg', то это значит, что при обращении model_name.img.url (обратите внимание, что мы обращаемся к атрибуту url поля img модели model_name) будет возвращено что-то типа /media/path/to/my/photo.jpg, где /media/ — корень хранилища загружаемых файлов (по умолчанию задаётся в настройке MEDIA_URL и имеет значение "/media/").

    Советую переписать код.
    • Во-первых, при оформлении настоятельно советую поддерживаться PEP8.
    • Во-вторых, как уже рекомендовали выше, использовать requests.
    • В-третьих, использовать шорткаты, которые предоставляются Джангой. В данном случае я говорю про функцию render вместо пары HttpResponse(render_to_string) и метод get_or_create() у менеджера модели.
    • Избавиться от дублирования кода
    • Не использовать жадные except'ы. Ловить следует только те исключения, которые могут возникнуть штатно в процессе работы.


    С учётом вышеизложенного, Ваш код может выглядеть как-то так:
    from django.shortcuts import render
    import requests
    import requests.exceptions as rex
    
    def baza(request):
        # В этом месте мы скачали страничку по адресу BAZA_URL/
        try:
            page = requests.get("BAZA_URL")
            page.raise_for_status()
    
        # Попутно обработали ситуацию, если страница по каким-то причинам
        # недоступна (например, её переместили, сервер ушёл в даун или просто
        # сеть недоступна). Все остальные возможные ошибки мы в этом месте
        # не обрабатываем.
    
        except (rex.ConnectionError, rex.HTTPError) as ex:
            return HttpResponse("Unable to open BAZA_URL")
    
        baza = page.content.split('<br>')
    
        for line in page:
            # Здесь мы просто ввели локальные переменные для упрощения
            # кода. Согласитесь, когда в поле модели name нужно подставить
            # имя, то проще написать переменную name, чем высчитывать, какой
            # же это по счёту элемент массива :)
            #
            # К тому же, если вдруг формат данных изменится, код придётся
            # править только в одном месте. так что мы заодно избавились от
            # дублирования.
            cat_name, img_url, name, text, options = line.split('--')[:4]
    
            # Воспользовались шорткатом от Джанги. Модель будет взята из базы,
            # если на существует с таким именем. Если нет, то будет создана.
            # Тоже избавление от дублирования
            categories, created = Categories.objects.get_or_create(name=cat_name)
    
            # Создание модели Item с помощью метода create у менеджера. Сразу
            # же мы решаем здесь возможную проблему с сетью. Если какой-то файл
            # окажется недоступным, мы его не будем сохранять, а перейдём к
            # следующему
    
            try:
                pic = requests.get(img_url)
                pic.raise_for_status()
    
                Item.objects.create(categories=categories,
                                    img=ContentFile(pic.content),
                                    name=name,
                                    text=text,
                                    options=options)
            except (rex.ConnectionError, rex.HTTPError) as ex:
                # Пришлось немного продублировать код, потому что здесь
                # возможны те же ошибки, что и в самом начале вьюхи.
                continue
    Некоторые вещи я намеренно опустим (например то, что для всех HTTP-запросов с помощью requests можно использовать одно соединение, не создавая новое для каждого запроса)

    И ещё один совет: операции, которые выполняются длительное время и которые могут свалиться по независящим от Вас причинам, лучше не делать в цикле запроса-ответа, а вынести в фоновую обработку. Например, воспользоваться celery
    Ответ написан
    5 комментариев
  • Как поле user сделать default current user?

    @marazmiki
    Укротитель питонов
    Во-первых, убрать это поле из формы

    class HotelsForm(forms.ModelForm):
        class Meta:
            model = Hotels
            exclude = ['user']


    Во-вторых, во вьюхе подставлять значение:

    def add_hotels(request):
        if request.method == 'POST':
            formset = HotelsForm(request.POST, request.FILES)
            if formset.is_valid()
                hotels = formset.save(commit=False)   # Пока не записывать изменения в БД
                hotels.user = request.user
                hotels.save() # Теперь можно записать
                return redirect('/user/success')
            else:
                print formset.errors
        else:
            formset = HotelsForm()
        return render(request, 'add_hotels.html', {'formset': formset})
    Непонятно только, почему обычная форма называется формсетом. И почему модель названа во множественном числе.
    Ответ написан
    3 комментария
  • Оптимизация objects.all() для огромной БД. Как получить все и не зависнуть на N минут?

    @marazmiki
    Укротитель питонов
    При итерировании кверисет целиком загружается в память, отсюда и проблема. Решение, которое предложил Александр Втюрин, хоть и несколько топорное, будет работать: идея там верная. Несколько лет тому эта проблема стояла очень остро, поэтому даже появился широко известный в узких кругах Сниппет #1949, сделанный именно на этом принципе.

    Но начиная с Django версии, если не ошибаюсь, 1.4, появилось штатное средство, предназначенное для аналогичных целей — метод iterator() у кверисета.
    Ответ написан
    Комментировать
  • Как изменить максимальное время выполнение POST запроса?

    @marazmiki
    Укротитель питонов
    Начать нужно с того, что запускать какие-то долгие процессы в цикле запроса-ответа джанги — вообще не самая здравая идея.

    Обычно такого рода задачи отправляют выполняются отдельным процессом celery или каким-то подобным механизмом. Время выполнения задач (в нашем случае парсинга) в них некритично: фоновый процесс — не посетитель сайта. Подождёт, никуда не денется.

    P.S. а таймаут соединения можно установить. Например, в requests, популярной библиотеке для выполнения HTTP-запросов, это делается вот так.
    Ответ написан
    3 комментария
  • Как реализовать интеграцию с аффилейт программами?

    @marazmiki
    Укротитель питонов
    Отдавайте партнёрскую ссылку не напрямую, а через вьюху-прокладку, которая сохранит факт клика и всю сопутствующую информацию: текущего пользователя, дату-время, ip-адрес, реферер, имя браузера, id сессии — словом всё, что можно вытащить из реквеста.
    Ответ написан
    3 комментария
  • Какую ресайзилку изображений лучше использовать для Django и S3?

    @marazmiki
    Укротитель питонов
    Исходя из личного опыта: sorl-thumbnail — кровососина. Не потому что жмёт как-то не так, а потому что периодически теряет кеш, генгерирует тумбнейлы заново, а старые остаются сиротливо лежать на старом месте.

    Когда используется облачное хранилище с оплатой за ресурсы, это дико напрягает. Опять же, из личного: на проекте, в котором были миллионы картинок, очистка кеша, хранящегося в Selectel Storage, заняла почти два месяца непрерывной работы. Сколько ушло лишних денег на оплату этого хранения, вспоминать не очень хочется.

    В конечном счёте для того проекта я использовал thumbor — сервис для генерации тумбнейлов (он, правда, standalone, но вроде существуют попытки перенести его хранилища в S3). За ~полгода использования мысли такие: по сравнению с сорлом небо и земля. И скорость в разы больше, и RESTful-апи встроенное, и алгоритмы кропа изображений субъективно умнее.

    Ставится, конечно, чуть сложнее, но оно того стоит. Очень рекомендую осилить.
    Ответ написан
    1 комментарий
  • Свои кнопки(функции) в админке джанги?

    @marazmiki
    Укротитель питонов
    Админка по сути — старая версия CBV. С тем лишь отличием, что задаёт не единственную вьюху, а набор. И схему урлов бонусом. И есть штатные средства добавить в каждый класс ModelAdmin приоизвольный набор собственных вьюх-действий. Даже в документации указано.

    Как сделать кнопки: не знаю, как насчёт сейчас, но ещё буквально год назад для этого нужно было переопределять шаблон админки для конкретного приложения (см. про переопределение шаблонов в админке). Или более простой вариант — написать JS, который добавит на страничку HTML-код кнопок, и подключить этот JS через Media.
    Ответ написан
    Комментировать
  • Как сделать midleware в django, который меняет TEMPLATE_DIRS?

    @marazmiki
    Укротитель питонов
    Когда Вы делаете такие штуки, нужно иметь в виду, что объект settings глобален. Вот зайдёте Вы с мобильной версии, миддльварь сменит TEMPLATE_DIRS. А сразу же следом за Вами (пока джанга не успела начать рендерить шаблон) — кто-нибудь с компьютера. И значение TEMPLATE_DIRS вернётся в исходное.

    Ключевое слово для поиска решения — thread locals.
    Ответ написан
    9 комментариев