2013-11-19 3 views
1

У меня есть класс, который имеет отношения родитель-потомок:SQLAlchemy: найти дочерние объекты в отношениях с NULL родителя

Base = declarative_base() 

class Parent(Base): 
    __tablename__ = "parent_table" 
    id = Column(Integer, primary_key=True) 
    children = relationship("Child", backref="parent") 
    def all_children(self): 
    pass # I want self.children + "Child where parent_id = NULL" 

class Child(Base): 
    __tablename__ = "child_table" 
    id = Column(Integer, primary_key=True) 
    parent_id = Column(Integer, ForeignKey('parent_table.id') 

Я хотел бы добавить функцию моего родителя, который возвращает детей родительские в отношения, а также все дочерние объекты, для которых столбец parent_id установлен в NULL.

Вся ситуация немного сложнее, потому что классы на самом деле являются примером объединенного наследования таблиц следующим образом: table_per_related, но я даже не знаю, с чего начать, поэтому, вероятно, сможет понять это оттуда.

(Все это должно быть полезной в контексте веб-сервиса через колба)

Edit: Update. Это минимальная реализация того, что я действительно хотел сделать, так как я не могу вполне удается перевести первый ответ в то, что работает в этом контексте:

from sqlalchemy.ext.declarative import declarative_base, declared_attr 
from sqlalchemy import Column, Integer, String, ForeignKey 
from sqlalchemy.orm import relationship 

from sqlalchemy.orm import Session 
from sqlalchemy import create_engine 

class BaseCols: 
    id = Column(Integer, primary_key=True) 
    name = Column(String) 

    def __repr__(self): 
    return "<{}: {} - {}>".format(self.__class__.__name__, self.id, self.name) 

    @declared_attr 
    def __tablename__(cls): 
    return cls.__name__.lower() 

Base = declarative_base(cls=BaseCols) 

class Child(BaseCols): 
    pass 

class HasChild: 
    @declared_attr 
    def children(cls): 
    cls.Child = type("{}Child".format(cls.__name__), 
        (Child, Base,), 
        dict(
          __tablename__="{}_children".format(cls.__tablename__), 
          parent_id=Column(Integer, ForeignKey("{}.id".format(cls.__tablename__))), 
          parent=relationship(cls) 
        ) 
        ) 
    return relationship(cls.Child) 

    def all_children(self): 
    pass 

class Foo(Base, HasChild): 
    __tablename__ = 'foo' 
    __mapper_args__ = {'concrete': True} 

class Bar(Base, HasChild): 
    __tablename__ = 'bar' 
    __mapper_args__ = {'concrete': True} 


if __name__ == "__main__": 
    engine = create_engine('sqlite://', echo=True) 
    Base.metadata.create_all(engine) 

    session = Session(engine) 

    session.add_all([ 
    Foo(
     name = "Foo the first!", 
     children = [ 
     Foo.Child(name="Heir Apparent."), 
     Foo.Child(name="Spare.") 
     ] 
    ), 
    Foo(
     name = "Foo the second...", 
     children = [ 
     Foo.Child(name="Some child."), 
     ] 
    ), 
    Bar(
     name = "Bar the first!", 
     children = [ 
     Bar.Child(name="Bar's.") 
     ] 
    ), 
    Foo.Child(name="whoops"), 
    ]) 

    session.commit() 

    foo1 = session.query(Foo).first() 
    print(foo1) 
    print(foo1.children) 
    print(foo1.all_children(session)) 

ответ

2

Что-то вроде этого?

class Child(Base): 
    # ... 

class Parent(Base): 
    # ... 
    def all_children(self): 
     return Child.query.filter((Child.parent_id == self.id) | (Child.parent_id == None)).all() 

Обратите внимание, что я переехал Child класс выше Parent, так что можно ссылаться в all_children().

Update: Вот реализация для кода вы добавили на свой вопрос:

def all_children(self, session): 
     cls = self.__class__.Child 
     return session.query(cls).filter((cls.parent_id == self.id) | 
      (cls.parent_id == None)).all() 
+0

Да! У меня все еще есть несколько деталей, которые можно найти с помощью table_per_related setup, но отправьте сообщение, если я столкнусь с другими трудностями. Поскольку я не сталкивался с этим в своих поисках, где документирован синтаксис Class.query? – kai

+1

Синтаксис 'class.query' от Flask-SQLAlchemy. Если вы используете простой SQLAlchemy, эквивалентным синтаксисом является 'session.query (Class)'. См. Http://docs.sqlalchemy.org/en/rel_0_9/orm/query.html – Miguel

+0

Ах, правильно. Глядя в совершенно неправильное место тогда. – kai

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