Перейти к содержимому
На этой странице

Django ORM и базы данных

Все темы Python Developer

Чем aggregate() отличается от annotate()?

aggregate() завершает QuerySet и возвращает один словарь со сводными значениями. annotate() добавляет вычисленное поле каждой строке результата; вместе с values() оно задает группировку. JOIN по нескольким связям может размножить строки и исказить суммы, поэтому проверяют SQL и при необходимости используют distinct, подзапрос или отдельные агрегации. Агрегаты по пустому набору часто дают NULL. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.


Как MVCC выбирает видимую версию строки?

PostgreSQL хранит версии строк. Snapshot определяет, какие транзакции считаются видимыми, а служебные xmin и xmax описывают создание и завершение жизни версии. Обычный SELECT обычно не блокирует запись, но записи могут конфликтовать между собой. Старые версии превращаются в dead tuples; autovacuum освобождает их для повторного использования, а долгие транзакции мешают очистке. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.


Когда нужен SELECT FOR UPDATE?

SELECT ... FOR UPDATE нужен внутри транзакции для сценария read-check-write: выбранные строки блокируются от конкурирующего изменения до завершения транзакции. Обычное чтение блокировка не заменяет. Транзакцию держат короткой, строки берут в стабильном порядке и задают политику ожидания, например timeout, NOWAIT или SKIP LOCKED в PostgreSQL, чтобы управлять дедлоками и очередями. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.


Как обработать ошибку внутри ORM-сессии?

Сессию и транзакцию открывают на четкой границе операции. При ошибке делают rollback до повторного использования сессии, затем освобождают ее через контекстный менеджер или finally. Повторяют только классифицированные временные ошибки, например serialization failure или разрыв, и только если операция идемпотентна. Ошибку ограничения данных не лечат слепым retry; ее переводят в понятную доменную ошибку. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.


Что гарантируют миграции схемы?

Миграции дают версионированный граф изменений схемы и воспроизводимый порядок их применения. Они не гарантируют безостановочность, обратимость каждого DDL или корректность преобразования данных. Большую data migration отделяют, делают повторяемой и наблюдаемой. Перед rollout проверяют поведение конкретной СУБД и версии, блокировки и совместимость старого и нового приложения во время поэтапного деплоя. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.


Как разложить задержку запроса к БД по слоям?

Задержку раскладывают на ожидание соединения в пуле, сеть, ожидание блокировки, выполнение плана в БД и передачу или десериализацию результата. Нужны тайминги на каждой границе, slow query log и состояние активных транзакций. EXPLAIN ANALYZE подтверждает фактические строки и время операторов, но сам выполняет запрос, поэтому с изменяющими запросами и production-нагрузкой его применяют осторожно. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.


Как найти запросы с наибольшей суммарной нагрузкой?

В PostgreSQL pg_stat_statements сортируют по total_exec_time, числу вызовов, среднему времени и чтениям, чтобы отличить редкий медленный запрос от частого дорогого. pg_stat_activity показывает текущие запросы и waits, а системные представления блокировок находят очередь. Затем выбранный нормализованный запрос проверяют через EXPLAIN (ANALYZE, BUFFERS) на безопасном примере и со свежей статистикой. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.


Когда Django QuerySet выполняет SQL?

Django QuerySet ленив: фильтры строят запрос, а SQL обычно выполняется при итерации, list(), len(), bool(), срезе с шагом и других операциях, требующих результата. После оценки QuerySet кэширует строки для повторного обхода того же объекта. Новый QuerySet или .all() может выполнить запрос заново. Методы exists, count, update и delete отправляют свои запросы сразу. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.


Как типизировать модель SQLAlchemy 2.0?

В SQLAlchemy 2.0 поля декларативной модели описывают как Mapped[T] = mapped_column(...), а связи как Mapped[Related] или коллекцию. T | None должно согласовываться с nullable=True; это разные уровни, но расхождение вводит в заблуждение. Тип связи отражает кардинальность, а relationship не является колонкой. Аннотации помогают анализатору и мапперу, но не валидируют вход API. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.


Как устранить N+1 в Django ORM?

N+1 находят по числу SQL-запросов при сериализации списка. select_related делает JOIN для одиночных ForeignKey и OneToOne; prefetch_related выполняет отдельный запрос и связывает в Python коллекции и many-to-many. Выбор зависит от кардинальности и объема. Предзагрузка всего графа тоже может быть дорогой, поэтому фиксируют нужные связи и проверяют число запросов тестом или профилировщиком. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.


Когда OFFSET pagination перестает работать эффективно?

Глубокий OFFSET заставляет СУБД найти и отбросить все предыдущие строки, поэтому время растет. При параллельных вставках и удалениях страницы также получают дубли или пропуски. Для длинной ленты используют keyset pagination: стабильный уникальный ORDER BY и условие после последнего ключа, например по (created_at, id). OFFSET остается удобным для небольших административных выборок и перехода к номеру страницы. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.


Как порядок столбцов влияет на составной индекс?

Составной B-tree индекс полезен запросам, использующим его левый префикс; точные правила зависят от СУБД и условий. Порядок выбирают по реальным WHERE, диапазонам и ORDER BY, а не по одной лишь селективности столбца. Каждый индекс занимает место и удорожает запись. Решение подтверждают планом и статистикой на похожих данных, потому что оптимизатор может предпочесть full scan. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.


Как безопасно выполнить raw SQL в Django?

В Django значения передают отдельными параметрами через raw() или connection.cursor(), не склеивают строку и не подставляют кавычки вручную. Имена таблиц и столбцов параметрами не становятся, их выбирают из разрешенного набора и корректно quote-ят средствами backend. Запрос помещают в нужную транзакцию, документируют диалект СУБД, проверяют план и покрывают интеграционным тестом. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.


Почему сервису нужен ограниченный пул соединений?

Каждое соединение расходует память и работу БД, а тысячи конкурентных запросов создают contention вместо роста throughput. Лимит пула рассчитывают из общего бюджета БД на все реплики и фоновые процессы. Когда пул занят, ожидание создает управляемый backpressure; у него должен быть timeout и метрика. Соединение всегда возвращают в пул, завершая или откатывая транзакцию, иначе утечка быстро исчерпает лимит. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.


Когда ALTER TABLE переписывает большую таблицу?

Цена ALTER TABLE зависит от СУБД, версии и конкретной операции. Смена типа, materialized default, проверка существующих строк или некоторые изменения хранения могут переписать таблицу; создание индекса и validation долго читают данные и берут блокировки разной силы. Перед production rollout проверяют документацию своей версии и репетицию на копии, используют совместимые фазы expand-migrate-contract и готовят откат приложения. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.


Какие риски есть у ON DELETE CASCADE?

ON DELETE CASCADE удобно поддерживает ссылочную целостность, но одно удаление может запустить большую и неожиданную цепочку, долго держать блокировки и раздувать транзакционный лог. Внешние ключи дочерних таблиц обычно индексируют, чтобы поиск зависимостей не сканировал их целиком. Для важных сущностей часто нужна явная бизнес-операция, аудит или soft delete. Массовое удаление репетируют и ограничивают пакетами. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.


Когда GenericForeignKey хуже обычного ForeignKey?

GenericForeignKey хранит пару content_type и object_id, позволяя ссылаться на модели разных типов. Цена: обычный внешний ключ БД не гарантирует существование цели, каскады и запросы сложнее, select_related не работает как для нормальной связи. Если набор целей известен, отдельные ForeignKey, общая таблица или явная модель связи обычно надежнее. Полиморфизм оправдан только реальным доменным требованием. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.


Какую ответственность должен иметь ModelViewSet?

ModelViewSet связывает стандартные CRUD actions с queryset, serializer, permissions и router. Он должен адаптировать HTTP-вход, выбрать данные, вызвать прикладную операцию и сформировать ответ. Длинные транзакции, правила домена и интеграции лучше вынести в сервисы или модели с ясной границей. При этом не нужна абстракция ради абстракции: простая проверка, относящаяся только к endpoint, может остаться во ViewSet. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.


Когда SerializerMethodField создает N+1?

SerializerMethodField вызывает get_<field> для каждого сериализуемого объекта и является read-only. Если метод каждый раз обращается к непрефетченной связи или выполняет aggregate, список создает N+1. Данные заранее добавляют через select_related, prefetch_related или annotate, а метод читает подготовленное значение. Число запросов проверяют на списочном endpoint, потому что один объект проблемы не показывает. Вывод подтверждают фактическим SQL, числом запросов и планом на данных, похожих на production.

Собеседования: Python

Смотри записи интервью, узнай, какие вопросы задают и как отвечают кандидаты.

Вопросы и ответы

Не нашли ответ? Напишите мне в чат. Я делаю Шпаргалку и сам отвечаю на сообщения. Расскажите, что не работает или чего вам не хватает. Может, смогу сразу взять это в работу.

Откуда взяты вопросы?

Из реальных собеседований. Основой подборки стал опыт Вадима Новосёлова: он проходил интервью и записывал вопросы. Подробнее о материалах.

Насколько эти вопросы актуальны?

Эти вопросы встречались нам на реальных собеседованиях в 2025 году. Мы регулярно проходим собеседования и пополняем подборку новыми вопросами. Основы профессии и ключевые технологии остаются востребованными годами, а детали конкретных инструментов и версий стоит сверять с текущей документацией.

На какой уровень рассчитана подборка?

Мы проходили собеседования на вакансии уровня Middle+, а иногда и на Senior-позиции. Вопросы из этих интервью вошли в подборку. Направления работы: Python-разработчик, Backend-разработчик на Python. Глубина обсуждения зависит от вакансии: будь готов объяснить основную идею, привести практический пример и разобрать ограничения и альтернативы решения.

Этот вопрос точно будет на моём собеседовании?

Гарантии нет: набор вопросов зависит от компании, задач команды, уровня вакансии и самого интервьюера. Эти вопросы уже встречались на реальных собеседованиях, но на твоём интервью ту же тему могут проверить другой формулировкой, практической задачей или обсуждением твоего опыта. Используй подборку, чтобы разобраться в теме: объясняй идею своими словами, приводи примеры и готовься обсудить ограничения и альтернативы решения. Так будет проще ответить и на знакомый вопрос, и на неожиданные уточнения.