2014-02-11 3 views
0

Из кода ниже я определил отношения, как это: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?

ответ

0

Для этого вы должны использовать пользовательскую форму 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() --that является, выполняя обработку запросов и фильтрации на сервере SQL - вместо того, чтобы делать это в Python с помощью filter(). Первый занимает больше времени для кода и тестирования, но почти всегда будет быстрее, потому что SQL-серверы оптимизированы для него; последний занимает меньше времени для кодирования и на практике только вызывает проблемы с производительностью, когда вы выполняете множество запросов, которые возвращают много результатов. Лично я пишу вещи в Python, а затем выполняю медленные запросы через SQL.

+0

Это должно быть один к одному на самом деле. Я должен был оставить «тег» или добавить его в соединение, так как он на самом деле всегда 0 и не используется (но не мое занятие). Я обновил вопрос, чтобы не использовать много к одному (надеюсь). Я также не хочу подзапроса, но прямое внешнее соединение, где plan_ou должен быть установлен в условии соединения, а не внизу. Я еще проверю 'assoc_proxy'. – Asken

+0

Чтобы получить прямое соединение без подзапросов, вы можете сопоставить 'UnitTypeRowModel' против 3-х табличного соединения. Вы уже делаете это соединение каждый раз, когда вы запрашиваете 'UnitTypeRowModel', на самом деле, из-за ваших' lazy = join' ключевых слов в ваших отношениях. Если вы хотите обеспечить доступ только для чтения из класса 'UnitTypeRowModel', я думаю, вам придется запускать их через свойство python, чтобы предотвратить легкую запись. Дайте мне знать, если вы хотите увидеть код для любого из них, и я обновлю ответ. –

+0

Да, и я получаю все, что хочу, но я хочу добавить фильтр в plan_ou из объединения PlanPmValues ​​при запросе. – Asken

Смежные вопросы