Ответы пользователя по тегу Django
  • Django добавление атрибутов в input через if?

    @marazmiki
    Укротитель питонов
    А что будет, если кто-то из этих остальных пользователей через инспектор уберёт атрибут readonly из поля, изменит значение и отправит форму? :)

    Как средство защиты readonly — ну такое.

    Я бы посоветовал просто вывести поля, стилизовав их под форму. Остальные решения подразумевают создание собственных форм, виджетов и тому подобных сущностей, использование которых является оверкиллом
    Ответ написан
  • Как организовать тесты в django на уровне app?

    @marazmiki
    Укротитель питонов
    Чисто субъективно, лучше выбрать что-то из одно: или размещать тесты на уровне приложений, или использовать pytest.

    Хранить тесты внутри приложений полезно при использовании стандартного джанговского тест-раннера: он знает и умеет их находить и запускать. Pytest же не является родным инструментом для джанги, соответственно, использует свой механизм дискаверинга тестов.

    Если Вы нацелены именно на реюзабельные приложения (я полагаю, это означает вынос их в отдельные пакеты и размещение в индексах типа PyPI или собственных частных?), я бы порекомендовал поступать следующим образом:
    • Создавать приложения в отдельном репозитории, вне Вашего основного проекта;
    • Не забывать про setup.py и setup.cfg; либо познакомиться с замечательным пакетом poetry, который снимет кучу головняка с моментами, связанными с упаковкой и публикацией пакетов. Он и в разработке основного проекта очень поможет, но речь сейчас не об этом :)
    • Писать тесты с использованием pytest. Это гораздо мощнее и удобнее, чем родной джанговский раннер
    • Размещать тесты вне директории питоновского пакета, т.е. вашего django-приложения, и вообще не помещать их в архив пакета. В конце концов, тесты — они про разработку, а не про продуктив, на боевой машине не нужны
    • Создать минималистичный джанго-проект внутри директории тестов и не добавить в его urls ссылку на URLConf Вашего приложения
    • И, как следствие, не бойтесь тестировать вьюхи так, как будто они уже часть проекта (так и есть, собственно). Конечно, никто не запретит конструировать объект request и вызывать вьюхи как обычные функции, передавая этот request в виде первого аргумента, но мы ведь тестируем не для покрытия, а для того, чтобы работало, правда?



    Ответ написан
  • Как правильно добавить файлы миграций в gitignore?

    @marazmiki
    Укротитель питонов
    Правильно — никак. Миграции являются неотъемлемой частью проекта, не нужно их исключать.
    Ответ написан
  • Как в Django организовать миграцию для двух связанных моделей с автоматической подстановкой дефолтных значений поля?

    @marazmiki
    Укротитель питонов
    Сценарий для джанги я бы предложил такой:
    1. Создать модель ModelY, сгенерировать и применить соответствующую миграцию.
    2. Добавить в Model необязательный (т.е. null=True) внешний на ModelY. Сгенерировать миграцию и применить её.
    3. Создать дата-миграцию, в которой создадим "дефолтный" объект ModelY. Накатить её.
    4. Изменить внешний ключ (см. п.2) таким образом, чтобы он подставлял дефолтное значение. Пока не убирать null=True. Накатить. Теперь все вновь созданные модели будут создаваться правильно
    5. Создать дата-миграцию, которая заменила бы все нулевые внешние ключи на дефолтный объект. Накатить.
    6. Теперь можно сделать внешний ключ из п.2. обязательным, т.е. убрать null=True.


    Что же касается best practices, то из опыта я бы посоветовал следующее:

    • Не надо пытаться минимизировать число миграций или засунуть всё в одну. Напротив, лучше идти по пути упрощения миграций, а не уменьшия их количества.
    • Миграции лучше делать максимально независимыми друг от друга.
    • Не нужно заморачиваться с two-way; если какое-то решение оказалось неудачным, лучше сделать ещё одну миграцию, которая делает противоложную операцию относительно предыдущей, чем откатываться.
    • Если добавляете новое поле, обязательно делайте его сперва null, а лишь потом заполняйте.
    Ответ написан
  • Почему форма ведет себя странно?

    @marazmiki
    Укротитель питонов
    Подозреваю, что у Вас вот тут сustomer = form.save(commit=False) опечатка. Скорее всего, вместо английской "C" набрана русская "С" :)
    Ответ написан
  • Как избавиться от ошибки 1064 You have an error in your SQL syntax?

    @marazmiki
    Укротитель питонов
    Думаю, дело обстоит так: проект был создан относительно давно, а Вы пытаетесь его актуализировать и обновлять зависимости. С кодовой базой сложностей нет, а вот cleardb, похоже, застрял в прошлом и работает на основе древнего mysql 5.5, поддержку из которого выпилили то ли в версии 2.0, то ли 2.1 Джанги. Отсюда и непонятки: джанга генерирует современный SQL, который старый Мускуль не в состоянии распарсить.

    Проще всего именно эту ошибку исправить, заманкипатчив джангу в момент запуска проекта :
    # settings.py
    
    from django.db.backends.mysql.base import DatabaseWrapper
    
    DatabaseWrapper.data_types['DateTimeField'] = 'datetime'
    Но надо понимать, что это всего лишь костыль, чтобы быстро запуститься. Поэтому потом всё же лучше актуализировать движок базы.
    Ответ написан
  • Какие инструменты использовать при поиске в базе с большими данными?

    @marazmiki
    Укротитель питонов
    Если про фасетирование речь, то лучше всего, на мой взгляд, использовать elasticsearch. Но не обязательно, если уже используете Postgres.
    Ответ написан
  • Запустить Angular и Django одной командой?

    @marazmiki
    Укротитель питонов
    Я так понимаю, что ng build --watch запускается в терминале и, таким образом, пока не завершится, следующие команды не будут выполяться, что логично.

    Запускайте его в фоне через nohup.

    Ну или docker-compose попробуйте :)
    Ответ написан
  • У меня версия джанго 2.1 и как я знаю что в urls.py нужно писать path вместо url?

    @marazmiki
    Укротитель питонов
    Начиная с версии 2.0, все штуки, связанные с обарботкой урлов, хранятся в django.urls, а не django.conf.urls, как ранее. Старый url() доступен в этом пакете, вероятно, для совместимости.

    Подробнее в описании релиза (см. последний абзац)
    Ответ написан
  • Как задать в ContentType только 2 модели?

    @marazmiki
    Укротитель питонов
    Используйте limit_choices_to. Принципиально решение будет выглядеть примерно так:

    from django.db.models import Q
    class Slider(models.Model):
       # ...
        content_type = models.ForeignKey(
            ContentType,
            limit_choices_to=Q(app_label='app_1', model='modelclass1') | Q(app_label='app_2', model='modelclass2')
        )
        object_id = models.PositiveIntegerField()
        content_object = GenericForeignKey('content_type', 'object_id')    
       
        # ...


    Нового тут особо ничего не придумаешь, но есть есть возможность украсить код, например, написав функцию (limit_choices_to может принимать callable-объект, возвращающий dict или Q):

    from operator import or_ as OR
    from functools import reduce
    from django.apps import apps
    from django.db.models import Q
    
    def limit(*models):
        """
        Динамически построит выражение Q для списка заданных в аргументе моделей.
        """
        return reduce(OR, [Q(
            app_label=apps.get_model(m)._meta.app_label,
            model=apps.get_model(m)._meta.model_name) for m in models
        ])
    
    
    class Slider(models.Model):
        # ...
        content_type = models.ForeignKey(
            ContentType,
            limit_choices_to=limit('app_1.ModelClass1', 'app_2.ModelClass2'),
        )
        object_id = models.PositiveIntegerField()
        content_object = GenericForeignKey('content_type', 'object_id')    
        # ...


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

    class Slider(models.Model):
        content_object = LimitedGenericForeignKey(
            allowed_models=['app_1.ModelClass1', 'app_2.ModelClass2']
        )


    Но это оставлю на домашнее задание :)
    Ответ написан
  • Проблема после обновления django?

    @marazmiki
    Укротитель питонов
    В Django 1.11 изменили систему виджетов: раньше генерируемый ими HTML был захардкожен, теперь же используются шаблоны.

    Вероятно, приложение в пакете pagedown (не знаю, что это такое, но быстрый поиск показал, что существует некий django-pagedown, который в принципе похож) ещё не обновилось. Или Вы его не обновили. Попробуйте сделать pip install --upgrade django-pagedown (если я угадал с приложением, конечно)
    Ответ написан
  • Как организовать хранение файлов на сервере?

    @marazmiki
    Укротитель питонов
    Правильно ли я понимаю что для хранение файлов их нужно разбивать по папкам,

    Неправильно.
    Для того, чтобы файлы загружались и благополучно отдавались, сегментировать (разбивать по папкам) их совсем не обязательно.

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

    А на боевых серверах использование хранилища в локальной файловой системе и вовсе нонсенс. Там эта проблема не стоит в принципе.

    Сегментацию можно сделать для, скажем так, красоты. Или чтобы было понятно, кому принадлежит тот или иной файл. Но практическая польза от неё сомнительна. Вреда, впрочем, тоже нет :)

    допустим на сервер пользователь с Ником username заливает файл file.mp4, и я сохраняю этот файл по пути u/us/use/user/usern/file.mp4 и такой путь формируется для каждого пользователя

    Опять неправильно.

    Во-первых, никогда, НИКОГДА не доверяйте данным, пришедшим от пользователя. Сохраняете загруженный файл – сгенерируйте имя сами. А оригинальное имя не возбраняется сохранить и в другом месте. Если понадобится дать возможность пользователю сохранить файл под оригинальным именем, это делается в несколько строк.

    Во-вторых, Ваша сегментация слишком агрессивная. Если представить, что юзернейм может состоять только из строчных латинских букв и цифр (итого алфавит 26+10=36 символов), то такое хранилище сможет вместить 36 ^ (1 + 2 + 3 + 4 + 5) = 36^15 = 2.21 * 10^23 файлов без повторений. А что если юзернейм короче 5 символов? А что если он переименуется?

    Помните "во-первых"? Так как нам нужно самим придумать имя файла, почему бы не воспользоваться либо UUID и сгенерировать уникальное (с высокой достоверностью) значение вида 28c5a6d8-f7b5-440f-aeaa-150e4fd0bebc, а его уже сегментировать? Например, два сегмента по два символа датут прикольные ссылки вида 28/c5/28c5a6d8-f7b5-440f-aeaa-150e4fd0bebc и возможность разместить 65 тысяч файлов так, чтобы они были по одной штуке в директории :)

    Есть также вариант использовать не UUID, а посчитать контрольную сумму файла и взять её в качестве имени. Практическая ценность такого хеша, правда, тоже стремится к нулю :)

    если будет 2 одинаковых названия файла у одного пользователя то просто добавляю к новому файлу номер (file1.mp4)

    Если речь идёт о Джанге, то она сама так делает, это штатная функция хранилища.
    Ответ написан
  • Как в одном проекте Django оптимально реализовать сайты на поддоменах в разных городах?

    @marazmiki
    Укротитель питонов
    Плюсы первого способа — независимость баз друг от друга, как ни парадоксально. Это значит, что если одна из них ляжет, то остальные могут работать. Или, например, если база для Москвы сильно разрослась, то её можно легко перекинуть на другой сервер. Но в этом случае говорить об одной инстанции Джанго с динамическим переключением роутеров – не лучшая идея. Минусы — геморрой с поддержкой как базы, так и серверов приложений.

    Второй способ мне кажется более приемлемым. Основное достоинство в простоте. Положа руку на сердце, мало какой проект выстреливает так, чтобы была реальная необходимость делить его на базы. Вы скорее в теоретический потолок джанги упрётесь. А значительный объём, на который увеличится БД... не надо заниматься преждевременной оптимизацией. Если (ЕСЛИ!) проект выстрелит, то и опыта наберётесь, и мысли дельные появятся, специфические для конкретно этого проекта.

    И в данном случае я бы, пожалуй, сделал именно один экземпляр сервера приложений, с одним settings. Чтобы никаких настроек не переключать. Завёл бы модель Domain и миддльварьку, которая брала бы домен из текущего запроса, искала его в этой модели и помещала бы в request (по аналогии с user).

    Все настройки можно хранить в БД, используя в качестве признака как раз вышеописанный Domain. Это хорошо ещё и тем, что после изменения настроек не нужно будет перезапускать сервер.

    А sites framework – абсолютно бесполезная фигня, его использование оправдано только в одном случае: если используются очень нужные, но уже старые и давно не обновляющиеся батарейки, которые его требовали. Если у вас появилась уникальная возможность начать новый проект без легаси, то очень советую ей воспользоваться. Это непередаваемое ощущение, когда код чистый :)
    Ответ написан
  • Как оптимальным образом в Django проверить текст на наличие слов из базы?

    @marazmiki
    Укротитель питонов
    Если абстрагироваться от базы данных, то задача выглядит слегка проще. Считайте, что есть два множества: множество плохих слов и множество слов в тексте. Остаётся определить, пересекаются ли эти множества. Если пересекаются, то как минимум одно плохое слово есть :-)

    >>> a = { 1, 2, 3 }
    >>> b = { 2, 3, 4 }
    >>> c = { 5, 6 }
    >>>
    >>> a & b
    {2, 3}
    >>> a & c
    set()


    Теперь ближе к прикладной задаче. Поскольку множество "плохих слов" у нас хоть и хранится в БД (к слову, модели принято называть в единственном числе — BadWord — а не во множественном, как у Вас), но пока не происходят изменений, его можно считать статичным. Поэтому можно без зазрения совести брать это множество из кеша.

    # utils.py
    from django.core.cache import cache
    
    def get_bad_words():
        return cache.get('bad_words')


    и пересчитывать кеш при создании, редактировании или удалении записей из BadWords. Например, с помощью сигналов:

    # models.py
    def set_bad_words(**kwargs):
        from django.core.cache import cache
        cache.set('bad_words', {w.bword for w in BadWords.objects.all()})
    
    models.signals.post_save.connect(set_bad_words,  sender=BadWords)
    models.signals.post_delete.connect(set_bad_words, sender=BadWords)


    Теперь остаётся только преобразовать входящий текст в множество слов

    И пример использования:
    # utils.py
    
    def get_words_from_text(text_string):
        return set([w for w in text_string.lower().split()])


    и определять, есть ли плохие слова (т.е. пересекаются ли множества):

    # utils.py
    
    def has_bad_words(text_string):
        return bool(get_bad_words() & get_words_from_text(text_string))


    В общем, пространство для рефакторинга и улучшений ещё есть (неплохо бы вычистить из текста пунктуацию, стоп-слова, лишние пробелы, сигналы перенести в apps.py согласно новым правилам application loading, а то и вовсе выкинуть их), но идея, думаю, ясна.
    Ответ написан
  • Как импортировать настройки Django из самостоятельного скрипта?

    @marazmiki
    Укротитель питонов
    Рабочий (но неправильный) ответ — добавить директорию, в который лежат и apps, и standalone, в PYTHONPATH.
    Это делается двумя путями: или через переменную окружения PYTHONPATH при запуске из консоли:

    $ PYTHONPATH=. python standalone/syncaw.py

    либо добавить директорию прямо в скрипте:

    # syncraw.py
    import sys
    import os
    
    sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
    
    from apps.settings_local import *
    print(DEBUG)


    Правильный ответ — не делать так вообще. И отказываться от колхоза с settings_local
    Ответ написан
  • Как понять какой метод будет вызван в Django?

    @marazmiki
    Укротитель питонов
    А это и не нужно понимать. По крайней мере, я не могу представить такой кейс, когда это действительно нужно.

    Есть методы perform_create() и perform_update() у вьюхи или вьюсета. Есть create() и update() у сериалайзера. Пусть они реализуют конечную логику сохранения или создания объекта.
    Ответ написан
  • Как разбить на категории в админке в одном приложении?

    @marazmiki
    Укротитель питонов
    Можно ли стандартными средствами разбить пункты на группы, что бы отображались в разных блоках? Например, блок "ГЛАВНАЯ" и блок "ГЛАВНАЯ настройки"?

    Можно такое сделать и штатными средствами, но элегантность решения под вопросом. Идея заключается в следующем:
    1. В админке первого приложения app_1.admin не регистрировать модель app_1.Model1
    2. В приложении app_2 нужно создать прокси-модель app_2.Model2, указывающую на app_1.Model1.
    3. Зарегистрировать модель app_2.Model2 в админке второго приложения app_2.admin

    В итоге мы получим псевдо-модель во втором приложении, которая фактически находится в первом.

    Теоретически, наверное, можно даже создавать прокси-модель прямо в админке второго приложения app_2.admin, но здесь не уверен.
    Ответ написан
  • Как настроить маршрутизацию в Angular -route + Django?

    @marazmiki
    Укротитель питонов
    Поглядите в консоли разработчика, на какие адреса идут запросы к шаблонам, указанным в templateUrl. Сдаётся мне, Джанга вместо них отдаёт индексную страницу, которая инициализирует ангуляр, ищет роут, пытается загрузить шаблон, вместо него получает главную и так до упора.

    Если я угадал, то какие есть пути решения:

    1. Неправильный: класть все шаблоны ангуляра в директорию для статических файлов (см. staticfiles)

    2. Вообще не использовать Джанго для фронтэнда. Как бэкенд с API он отлично подходит, а вот для SPA и в частности для ангуляра — не очень. Я бы посоветовал разрабатывать SPA в отдельном репозитории, который ничего не знает про бэкенд.
    Ответ написан
  • Почему выскакивает ошибка MyUser' object has no attribute 'cleaned_data'?

    @marazmiki
    Укротитель питонов
    Потому что form = form.save(commit=False)

    Метод save() формы возвращает модель, у которой, разумеется, никакой cleaned_data нет.
    Ответ написан
  • Как дебажить Django на сервере?

    @marazmiki
    Укротитель питонов
    Воспользуйтесь Sentry. Можно как готовым сервисом пользоваться, можно установить копию на собственных мощностях.
    Ответ написан