Sqlalchemy и фильтр на отношения
Из приведенного ниже кода я определил отношения следующим образом:
UnitTypeRowModel (self-referencing but only one in the doc)
-- PlanPmDefinition (definition in the json doc)
-- PlanPmValues (value in the json doc)
Текущий результат как json, если у меня только один plan_ou в таблице базы данных:
[{
"children": [],
"parent_id": 1,
"id": 4
}, {
"children": [],
"parent_id": 2,
"plan_pm_id": 2,
"id": 5
"definition": {
"id": 2,
"tag": 0,
"value": {
"plan_pm_id": 2,
"tag": 0,
"plan_ou": 1
}
}
}]
Код:
class PlanPmValues(Base):
__tablename__ = 'plan_pm_municipal_values'
plan_pm_id = Column(Integer, primary_key=True)
tag = Column(Integer, primary_key=True)
plan_ou = Column(Integer) # Filter on this
...
class PlanPmDefinition(Base):
__tablename__ = 'plan_pm_municipal_definition'
id = Column(Integer, primary_key=True)
tag = Column(Integer, primary_key=True) -- always 0
value = relationship(PlanPmValues,
primaryjoin='and_(PlanPmDefinition.id==PlanPmValues.plan_pm_id, ' +
'PlanPmDefinition.tag==PlanPmValues.tag)',
foreign_keys='[PlanPmValues.plan_pm_id, PlanPmValues.tag]',
lazy='joined', uselist=False)
class UnitTypeRowModel(Base):
__tablename__ = 'unit_type_row_model'
__table_args__ = {'schema': base_schema}
id = Column(Integer, primary_key=True)
client_id = Column(Integer, ForeignKey(base_schema + '.client.id'))
parent_id = Column(Integer, ForeignKey(base_schema + '.unit_type_row_model.id'), nullable=True)
plan_pm_id = Column(Integer, nullable=True)
children = relationship(
'UnitTypeRowModel',
lazy='joined',
join_depth=2,
order_by="UnitTypeRowModel.sort_order")
definition = relationship(
'PlanPmDefinition',
primaryjoin='and_(PlanPmDefinition.id==UnitTypeRowModel.plan_pm_id, ' +
'PlanPmDefinition.tag==0)',
foreign_keys='[UnitTypeRowModel.plan_pm_id]',
lazy='joined',
uselist=False)
@staticmethod
def get_for_unit(client_id, unit_id):
db_session = DatabaseEngine.get_session()
row_models = db_session.query(UnitTypeRowModel).\
filter(UnitTypeRowModel.client_id == client_id).\
order_by(UnitTypeRowModel.sort_order)
json = util.Serialize.serialize_to_json(row_models)
db_session.close()
return json
Как мне отфильтровать plan_ou
из класса PlanPmValues
в методе UnitTypeRowModel.get_for_unit
?
1 ответ
Вы должны использовать обычай ColumnPropery
за это.
from sqlalchemy import select, and_
from sqlalchemy.orm import column_property
class UnitTypeRowModel(Base):
...
_ou_join = and_(plan_pm_id==PlanPmDefinition.id,
PlanPmDefinition.tag==PlanPmValues.tag,
plan_pm_id==PlanPmValues.plan_pm_id)
plan_ou = column_property(select([PlanPmValues.plan_ou],
whereclause=_ou_join).as_scalar())
Я сломал _ou_join
как отдельное свойство только для удобства чтения.
То, как вы определили это в своем коде SQLAlchemy, вы имеете отношение многие к одному UnitTypeRowModel
а также PlanPmDefinition
; и у вас есть отношения многие-к-одному между PlanPmDefinition
а также PlanPmValues
, Я предполагаю, что из uselist=False
аргументы обоих relationship()
звонки, и вы можете столкнуться с некоторыми другими ошибками, если вы не применили это в своей базе данных из-за использования уникальных ключей. Это означает, что полученное значение может вернуть только одну строку, которую я принудительно использовал as_scalar()
,
Как правило, вы обрабатываете запросы к связанным объектам, как это, используя association_proxy()
, Это не идеально в этом случае, потому что у вас уже есть и объект ассоциации (PlanPmDefinition
) между UnitTypeRowModel
а также PlanPmValues
; это означает, что association_proxy
позволит вам справиться PlanPmValue
объекты непосредственно из UnitTypeRowModel
класс, но не plan_ou
ценности.
Наконец, вы всегда должны проверять, что вам нужно сделать это как SQLAlchemy Query.filter()
- то есть выполнение запросов и фильтрации на сервере SQL - вместо того, чтобы делать это в Python через filter()
, Первый занимает больше времени для написания кода и тестирования, но почти всегда будет быстрее, потому что серверы SQL оптимизированы для этого; последний занимает меньше времени для написания кода и на практике вызывает проблемы с производительностью только тогда, когда вы делаете много запросов, которые возвращают много результатов. Лично я пишу вещи на Python, а затем делаю медленные запросы через SQL.