Как написать запрос через ORM для получения всех активных магазинов или магазинов с широтой больше нуля?
Что проверяют
Умеете ли вы выразить OR средствами ORM, а не собирать SQL строкой, и помните ли, что будет с NULL. Следом часто просят показать сгенерированный SQL или объяснить, как такой запрос ляжет на индексы.
Как отвечать
Дайте ответ для той ORM, что указана в вакансии, а лучше сразу для двух.
Django:
from django.db.models import Q
Store.objects.filter(Q(is_active=True) | Q(latitude__gt=0))Цепочка .filter(a).filter(b) или несколько аргументов в одном filter дают AND, поэтому для OR нужны объекты Q и оператор |. Сгенерированный SQL виден через print(qs.query).
SQLAlchemy 2.0:
from sqlalchemy import select, or_
stmt = select(Store).where(or_(Store.is_active, Store.latitude > 0))
stores = session.scalars(stmt).all()Детали, которые стоит назвать:
or_()или|: оба работают, но|в Python связывает сильнее сравнения, поэтому каждое условие берут в скобки;== True: работает, но линтер ругается (E712), идиоматично писать простоStore.is_activeили.is_(True);- стиль 2.0:
session.query()считается legacy, модели объявляют черезDeclarativeBase, а импортdeclarative_baseизsqlalchemy.ext.declarativeустарел ещё в 1.4; NULL: магазин сlatitude IS NULLиis_active = falseв выборку не попадёт, сравнение сNULLдаёт неtrue, а неизвестность.
Про производительность: в PostgreSQL на OR по двум колонкам планировщик может объединить два индекса через BitmapOr. Если одно из условий почти ничего не отсекает, будет последовательное чтение, и это нормально.
Где спотыкаются
Пишут питоновские or и and вместо | и or_(). В Django Q(...) or Q(...) молча вернёт первый объект, а в SQLAlchemy итог зависит от операторов: где-то TypeError, где-то тихо потерянное условие.
Пишут .filter(is_active=True).filter(latitude__gt=0) и получают пересечение вместо объединения.
Забывают скобки при | в SQLAlchemy: Store.is_active == True | Store.latitude > 0 разбирается как цепочка сравнений, совсем не так, как задумано.