Если в гибридном выражении указано необходимое имя пользователя, создается желаемый порядок
@created_by.expression
def created_by(cls):
return sql.select([User.first_name]).where(User.id == cls.created_by_id)
Хотя сгенерированный запрос добавляет дополнительный подзапрос, а не ссылается на таблицу с псевдонимом:
SELECT documents.id AS documents_id, documents.created_by_id AS documents_created_by_id, documents.deleted_by_id AS documents_deleted_by_id, users_1.id AS users_1_id, users_1.first_name AS users_1_first_name, users_2.id AS users_2_id, users_2.first_name AS users_2_first_name
FROM documents
LEFT OUTER JOIN users AS users_1 ON users_1.id = documents.created_by_id
LEFT OUTER JOIN users AS users_2 ON users_2.id = documents.deleted_by_id
ORDER BY (SELECT users.first_name
FROM users
WHERE users.id = documents.created_by_id)
Другой подход заключался бы в определении порядка в отношении:
creation_user = relationship("User", foreign_keys=[created_by_id], lazy="joined", order_by="User.first_name")
Это произвело SQL, указанное в вопросе, и устраняет необходимость в гибридных атрибутах:
SELECT documents.id AS documents_id, documents.created_by_id AS documents_created_by_id, documents.deleted_by_id AS documents_deleted_by_id, users_1.id AS users_1_id, users_1.first_name AS users_1_first_name, users_2.id AS users_2_id, users_2.first_name AS users_2_first_name
FROM documents
LEFT OUTER JOIN users AS users_1 ON users_1.id = documents.created_by_id
LEFT OUTER JOIN users AS users_2 ON users_2.id = documents.deleted_by_id
ORDER BY users_1.first_name
Однако если вам когда-нибудь понадобится другой порядок, вам нужно будет переопределить стратегию загрузки - см. этот ответ .