/main/
SQLAlchemy и order_by() для hybrid_property
Привет, Мир!
Много от кого слышал очень РАЗНЫХ мнений относительно SQLAlchemy
Лично я ловил очень много кринжатины, но абсолютным оверкилом оказалось сделать ORDER BY с помощью SQLAlchemy.
Имеем:
- SQLAlchemy
- postgresql
- гибридные поля
- какие-то обычные поля в БД
Кринжатина:
- SQLAlchemy не соблюдает дефолтное NULLS FIRST(DESC)/NULLS LAST(ASC) в постгресе, а зачем-то ВСЕГДА лепит NULLS FIRST
- есть огромная разница использования select(User).order_by(User.fullname.desc()) и использованием select(User).order_by(desc(User.fullname))
- гибридное поле должно возвращать ЗАПРОС, а не SQLColumnExpression
Если не будут соблюдены все эти условия ваше упорядочевание на гибридных свойствах или не будет работать, или будет возвращать неправильные результаты.
Вот, что заработало в моём случае, код гибридного свойства:
@related_clients_count.inplace.expression
@classmethod
def _related_clients_count_expression(cls) -> Select[Any]:
stmt: Select = select(func.count(RelatedClient.id)).filter( # pylint: disable=not-callable
RelatedClient.equipment_id == cls.id,
RelatedClient.is_operator == false(),
RelatedClient.is_active == true(),
)
return stmt
Код репозитория:
def _apply_ordering(self, statement: Select, ordering: pydantic.BaseModel | None = None) -> Select:
if ordering is None or not ordering.ordering: # type: ignore[attr-defined]
return self._default_ordering(statement=statement)
for enum_value in ordering.ordering: # type: ignore[attr-defined]
field: str = enum_value.value
order: UnaryExpression[Any]
nulls_order: UnaryExpression[Any]
if field.startswith('-'):
field = field[1:]
order = desc
nulls_order = nulls_first
else:
order = asc
nulls_order = nulls_last
try:
field_attr: InstrumentedAttribute = getattr(self.model, field)
statement = statement.order_by(nulls_order(order(field_attr)))
except AttributeError:
log.warning(f'Не удалось добавить сортировку для поля {field}, у модели отсутствует данный атрибут')
return statement
date: 07.08.2025
/main/