Django
Middleware, ORM, сигналы, DRF и аутентификация Django.
14 вопросов
JuniorТеорияОчень частоЧто такое Django ORM?
Что такое Django ORM?
Объектно-реляционный преобразователь: таблицы описываются классами models.Model, а запросы пишутся на Python через .objects.filter(...) вместо сырого SQL. Он генерирует SQL, ведёт миграции и отображает строки в экземпляры модели.
Типичные ошибки
- ✗Думать, что ORM — отдельная БД, а не слой над ней
- ✗Считать, что весь SQL всё равно надо писать руками
- ✗Забывать, что ORM ведёт миграции как часть работы
Уточняющие вопросы
- →Как
QuerySetлениво откладывает реальное выполнение SQL? - →Когда стоит опуститься до
raw()или.extra()SQL?
MiddleТеорияОчень частоКак устроена система аутентификации в Django?
Как устроена система аутентификации в Django?
Она даёт пользователей, группы, разрешения и сессии на cookie. AuthenticationMiddleware прикрепляет request.user к запросу; аутентификация проверяет личность по логину/паролю с хэшерами, авторизация — разрешения. OAuth — сторонний.
Типичные ошибки
- ✗Считать, что Django хранит пароли открытым текстом, а не хэшированными
- ✗Думать, что встроенных групп и разрешений нет
- ✗Полагать, что
request.userставит view, а неAuthenticationMiddleware
Уточняющие вопросы
- →Как сменный хэшер пароля обновляет старые хэши при входе?
- →В чём разница между аутентификацией и авторизацией здесь?
JuniorТеорияЧастоЧто такое внутренний класс Meta в модели или сериализаторе Django?
Что такое внутренний класс Meta в модели или сериализаторе Django?
Вложенный класс конфигурации с метаданными о внешнем классе — model, fields/exclude, сортировка, имя таблицы в БД — читается метаклассом Django при построении класса. Он настраивает класс, но сам не является полем.
Типичные ошибки
- ✗Объявлять поля данных внутри
Meta, а не в теле класса - ✗Считать
Metaбазовым классом для наследования, а не вложенной конфигурацией - ✗Полагать, что каждому обычному классу Python нужен
Meta
Уточняющие вопросы
- →Назовите три опции, задаваемые в
Metaмодели. - →Как
ModelSerializerиспользует свой внутреннийMeta?
JuniorТеорияЧастоЧто такое middleware в Django?
Что такое middleware в Django?
Подключаемый промежуточный слой, оборачивающий каждый запрос и ответ. Включается добавлением пути в MIDDLEWARE; записи идут сверху вниз на запросе и снизу вверх на ответе, и любая может проверить, изменить или вернуть свой ответ.
Типичные ошибки
- ✗Думать, что middleware видит только запрос и не может тронуть ответ
- ✗Забывать, что порядок в
MIDDLEWAREважен — запрос сверху вниз, ответ снизу вверх - ✗Считать, что middleware применяется к одной view, а не к каждому запросу
Уточняющие вопросы
- →В чём разница в порядке
process_requestиprocess_response? - →Как прервать запрос до того, как он дойдёт до view?
MiddleКодЧастоОтрефакторить две Django-модели с дублем полей amount и to_dict
Отрефакторить две Django-модели с дублем полей amount и to_dict
Вынесите общие поля amount_* и to_dict в абстрактную базовую модель — class AmountBase(models.Model): ... с class Meta: abstract = True — и наследуйте её в обеих моделях; абстрактные базы не создают таблицу, только наследуемые столбцы. Ключевая правка корректности: деньги во FloatField — баг (округление двоичного float) — используйте DecimalField. Также пересмотрите вольный null=True на полях amount/currency.
Типичные ошибки
- ✗Использовать конкретное наследование вместо абстрактной базы
- ✗Оставлять
FloatFieldдля денег вместоDecimalField - ✗Забывать
class Meta: abstract = True, из-за чего создаётся лишняя таблица
Уточняющие вопросы
- →Почему
FloatFieldневерен для денег, аDecimalFieldверен? - →Чем абстрактная базовая модель отличается от multi-table inheritance?
MiddleТеорияЧастоКак CSRF-middleware Django защищает POST-запросы?
Как CSRF-middleware Django защищает POST-запросы?
CsrfViewMiddleware кладёт случайный токен в cookie и требует от небезопасных методов (POST/PUT/DELETE) вернуть совпадающий csrfmiddlewaretoken в поле формы или заголовке; иначе — 403. GET освобождён, а @csrf_exempt снимает проверку с view.
Типичные ошибки
- ✗Считать CSRF-токен секретом как пароль, а не одноразовым значением запроса
- ✗Думать, что GET-запросы проверяются на CSRF-токен
- ✗Вешать
@csrf_exemptна view, чтобы заглушить 403, не понимая последствий
Уточняющие вопросы
- →Почему GET и HEAD освобождены от CSRF-проверки?
- →Как передать CSRF-токен из вызова fetch в JavaScript?
MiddleТеорияЧастоКак связь многие-ко-многим хранится на уровне базы данных?
Как связь многие-ко-многим хранится на уровне базы данных?
Отдельной промежуточной (связующей) таблицей с внешними ключами на обе стороны и доп. полями, ведь один столбец не может ссылаться на много строк. Запросы идут через неё по JOIN, и Django сам создаёт эту таблицу для ManyToManyField.
Типичные ошибки
- ✗Представлять m2m как список через запятую в одном столбце
- ✗Забывать, что связи нужна своя связующая таблица
- ✗Не знать, что поля к m2m добавляются через
through-модель
Уточняющие вопросы
- →Когда нужна явная
through-модель уManyToManyField? - →Как
JOINчерез связующую таблицу избегает дублей строк?
MiddleТеорияЧастоЧем select_related и prefetch_related различаются в Django?
Чем select_related и prefetch_related различаются в Django?
select_related делает SQL JOIN и тянет связанные строки одним запросом — только для одиночных связей (ForeignKey, one-to-one). prefetch_related выполняет отдельный запрос на каждую связь и соединяет их в Python — поддерживает many-to-many и обратный ForeignKey. Оба решают проблему N+1, загружая связанные объекты заранее, а не при каждом доступе.
Типичные ошибки
- ✗Путать, какой метод делает SQL
JOIN, а какой запрос на связь - ✗Применять
select_relatedк связи many-to-many - ✗Не понимать, что оба метода существуют для решения проблемы N+1
Уточняющие вопросы
- →Что за проблема N+1, которую решают эти методы?
- →Когда
prefetch_relatedсделает больше запросов, чем ожидалось?
MiddleТеорияЧастоЧто делает сериализатор Django REST Framework?
Что делает сериализатор Django REST Framework?
Он преобразует между экземплярами модели и примитивными типами вроде JSON: сериализует данные для ответов API и валидирует, а затем десериализует входящие данные в экземпляры. ModelSerializer выводит поля из модели через Meta.
Типичные ошибки
- ✗Думать, что сериализаторы только форматируют вывод и не валидируют ввод
- ✗Считать, что сериализатор шлёт запросы в БД напрямую, а не через модель
- ✗Забывать, что
ModelSerializerчитает поля из внутреннегоMeta
Уточняющие вопросы
- →Как
is_valid()связан сvalidated_dataиsave()? - →Когда писать обычный
SerializerвместоModelSerializer?
JuniorТеорияИногдаЧто такое сигналы (signals) в Django?
Что такое сигналы (signals) в Django?
Механизм публикации/подписки: компоненты испускают сигналы вроде pre_save и post_save, а зарегистрированные получатели реагируют. Доставка СИНХРОННА — внутри того же запроса, поэтому медленный получатель замедляет вызвавший его ответ.
Типичные ошибки
- ✗Считать, что сигналы идут асинхронно в фоне, а не синхронно
- ✗Ожидать срабатывания
post_saveна массовомqueryset.update()или.delete() - ✗Злоупотреблять сигналами там, где явный вызов метода был бы понятнее
Уточняющие вопросы
- →Почему злоупотребление сигналами усложняет чтение кода?
- →Как сделать так, чтобы получатель сигнала срабатывал лишь раз на процесс?
JuniorТеорияИногдаЧем Django и Flask различаются по философии?
Чем Django и Flask различаются по философии?
Django идёт «со всем в комплекте»: встроенные ORM, админка, аутентификация и шаблоны дают быстро запускать сайты. Flask — микрофреймворк с минимальным ядром: каждый компонент вы выбираете сами, что гибко для небольших сервисов.
Типичные ошибки
- ✗Считать, что Flask несёт встроенные ORM и админку, как Django
- ✗Думать, что Django нельзя настроить или заменить компоненты
- ✗Считать один строго лучше, а не подходящим под задачу
Уточняющие вопросы
- →Когда вы выберете Flask вместо Django на новом проекте?
- →Что создаёт
django-admin startproject, что Flask оставляет вам?
MiddleКодИногдаУпорядочить Django queryset по произвольному списку id в памяти
Упорядочить Django queryset по произвольному списку id в памяти
Аннотируйте каждую строку её позицией в списке через Case/When, затем упорядочьте по этой аннотации: preserved = Case(*[When(id=pk, then=pos) for pos, pk in enumerate(ids)]), затем MyModel.objects.filter(pk__in=ids).annotate(_order=preserved).order_by('_order'). База вычисляет выражение CASE для каждой строки, поэтому нужный порядок формируется в SQL, а не пересортировкой в Python.
Типичные ошибки
- ✗Считать, что
pk__inсохраняет порядок списка id - ✗Пересортировывать в Python вместо того, чтобы это делал SQL
- ✗Упорядочивать по
id, считая, что это совпадёт с произвольным порядком
Уточняющие вопросы
- →Почему
pk__inне гарантирует порядок своего списка-аргумента? - →Как выражение
CASEсопоставляет каждый id его позиции?
SeniorТеорияИногдаПочему CSRF-проверка Django освобождает GET и добавляет проверку referer на HTTPS?
Почему CSRF-проверка Django освобождает GET и добавляет проверку referer на HTTPS?
Безопасные методы (GET/HEAD/OPTIONS/TRACE) по HTTP обязаны быть без побочных эффектов, поэтому подделанный GET не навредит и освобождён. На HTTPS Django ещё сверяет Referer/Origin с доверенными хостами, блокируя MITM-инъекцию cookie.
Типичные ошибки
- ✗Считать GET освобождённым ради скорости, а не из-за отсутствия побочных эффектов
- ✗Думать, что проверка referer/origin идёт и на обычном HTTP
- ✗Считать, что CSRF-токен по умолчанию хранится на сервере в сессии
Уточняющие вопросы
- →Как заголовок
Originусиливает проверку на основеReferer? - →Почему независимый от сессии токен всё же побеждается MITM на HTTP?
MiddleДизайнРедкоМодель CurrencyRate хранит строки rate и datetime (например 34.9 на 1999-05-21, 70.3 на 2022-12-20). Спроектируйте Django-вьюшку, которая по запрошенному datetime возвращает курс, чей сохранённый datetime ближе всего к нему — ближайший может быть как до, так и после запроса (2022-12-19 даёт 70.3; 2000-05-21 даёт 34.9). Объясните стратегию запроса, почему наивный поиск в одну сторону неверен и как сохранить эффективность на большой таблице.
Модель CurrencyRate хранит строки rate и datetime (например 34.9 на 1999-05-21, 70.3 на 2022-12-20). Спроектируйте Django-вьюшку, которая по запрошенному datetime возвращает курс, чей сохранённый datetime ближе всего к нему — ближайший может быть как до, так и после запроса (2022-12-19 даёт 70.3; 2000-05-21 даёт 34.9). Объясните стратегию запроса, почему наивный поиск в одну сторону неверен и как сохранить эффективность на большой таблице.
Запросите обоих соседей: ближайшую строку на или после запрошенного времени (filter(datetime__gte=t).order_by('datetime').first()) и ближайшую на или до него (filter(datetime__lte=t).order_by('-datetime').first()), затем верните ту, у которой меньше модуль разницы времени. Наивный односторонний .first() игнорирует более близкую строку с другой стороны. С индексом по datetime каждый ограниченный запрос — поиск по индексу, эффективный даже на большой таблице.
Типичные ошибки
- ✗Проверять только одну сторону и упускать более близкого соседа
- ✗Загружать все строки в Python вместо ограничения поиска базой
- ✗Забывать индекс по
datetime, делая каждый поиск полным сканом
Уточняющие вопросы
- →Как решить это одним SQL-запросом вместо двух?
- →Какой индекс вы бы добавили и почему он ограничивает каждый запрос?