Ответы пользователя по тегу Django
  • Как пробросить в nginx адрес, на который хочет попасть юзер?

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

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

    @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 комментариев
  • Как установить permissions на ListCreateAPIView?

    @marazmiki
    Укротитель питонов
    Вот так:
    class PostList(generics.ListCreateAPIView):
        def get_permissions(self):
            if self.request.method  == 'GET':
                perms = [GetPermission]
            else:
                perms = [NotGetPermission]
            return [p() for p in perms]
    Понятно, что решение красотой не блещет, это, что называется, низкий уровень. Но в основе всех улучшений будет лежать именно этот принцип
    Ответ написан
    2 комментария
  • Как динамически переопределить widgets для ModelForm?

    @marazmiki
    Укротитель питонов
    Да, это штатная возможность:

    class RegistrationForm(forms.ModelForm) :
        error_css_class = 'error-form'
    Ответ написан
    Комментировать
  • Django + AngularJS, как увидеть traceback в консоли при ошибке?

    @marazmiki
    Укротитель питонов
    Насколько я помню, traceback выводится в консоли про DEBUG=False
    Ответ написан
    Комментировать
  • Как в Django CBV реализовать условие if/else?

    @marazmiki
    Укротитель питонов
    Наследование, конечно, позволит избавиться от дублирования кода, но есть два момента: во-первых, Вы меняете функциональное назначение get_object() и заставляете его что-то записывать, что само по себе некрасиво с точки зрения программиста :) если уж идти этим изначально неверным путём (ниже объясню почему неверным), то, думаю, красивее было бы переопределить dispatch().

    Во-вторых и главных, делать сохраняющие операции на HTTP-методы GET, HEAD и OPTIONS не рекомендуется никому. Хотя бы из тех соображений, что через несколько секунд после того, как Вы впервые их запросите, налетят всякие гуглоботы и накрутят счётчики. И хорошо ещё, если отказ в обслуживании не вызовут.

    Считается хорошим тоном и признаком здравого смысла использовать для сохраняющих вьюшек метод POST. Или, что ещё лучше, использовать RESTful-подход с POST, PUT и DELETE для создания, изменения и удаления соответственно.

    Конкретно в Вашем случае, мне кажется, для вьюхи инкременатции счётчика лучше всего использовать FormView. Или UpdateView, там уже реализован метод get_object().
    Ответ написан
    3 комментария
  • Как сделать расширенную модель пользователей?

    @marazmiki
    Укротитель питонов
    Логику создания и редактирования объектов очень удобно менять через сериализаторы. Но вообще, мне кажется, более правильный способ — перенести поле city в модель пользователя, благо вот уже как 3 мажорные версии джанга это умеет из коробки.
    Ответ написан
    5 комментариев
  • Какое выбрать решение для кеширования результатов функции?

    @marazmiki
    Укротитель питонов
    Есть позитивный опыт использования django-cacheops. На Хабре есть довольно полезная, хоть и довольно старая статья об использовании и настройке.
    Ответ написан
  • Чем сейчас модно деплоить django-проекты?

    @marazmiki
    Укротитель питонов
    Для деплоя используют то, что удобно. Нравится Фабрик — используйте Фабрик. Нравится Ансибль — используйте Ансибль (он, кстати, тоже не умеет в Python3). Поймите простую вещь: Вы ведь на своей машине запускаете fabric\ansible\whatever, не на боевом сервере. Поставьте python2.x рядышком
    Ответ написан
    3 комментария
  • Как получить все значения одного поля всех моделей в django?

    @marazmiki
    Укротитель питонов
    Ответ написан
    Комментировать