2011-08-04 10 views
6

las siguientes clases del modelo He declarado por SQLAlchemy:Cómo utilizar joinedload/contains_eager para las relaciones de consulta habilitada (opción = vagos 'dinámica') en SQLAlchemy

class User(Base): 
    id = Column(Integer, primary_key=True) 
    name = Column(String, nullable=False, unique=True) 
    created_at = Colmn(DateTime, nullable=False, default=func.now()) 

class Post(Base): 
    id = Column(Integer, primary_key=True) 
    user_id = Column(Integer, ForeignKey(User.id), nullable=False) 
    user = relationship(User, backref=backref('posts', lazy='dynamic')) 
    title = Column(String, nullable=False) 
    body = Column(Text, nullable=False) 
    created_at = Colmn(DateTime, nullable=False, default=func.now()) 

Como he citado, estos modelos tienen una relación y su fondo llamado posts configurado para ser consulta habilitado (a través de la opción lazy='dynamic'). Debido a que algunos usuarios pueden tener un gran conjunto de publicaciones, la mayoría de los usuarios no.

Con estos modelos, he intentado joinedload para User.posts, pero se enfrentaron el error:

>>> users = session.query(User).options(joinedload(User.posts))[:30] 
Traceback (most recent call last): 
    ... 
InvalidRequestError: 'User.posts' does not support object population - eager loading cannot be applied. 

¿Hay alguna manera de evitar esta situación? Necesito siguientes dos funcionalidades: ambos

  • veces User.posts se pueden cortar para evitar eagerloading del gran conjunto de mensajes escritos por los grandes consumidores.
  • Sin embargo, por lo general, User.posts no debería generar consultas 1 + N.

Respuesta

16

El problema es que la propiedad en User para publicaciones es una relación dinámica; Se supone que debe devolver un objeto Query. No hay forma de que la propiedad sepa, o se comunique de forma segura, que esta vez, todos los elementos relacionados ya están cargados.

La solución simple consistirá en tener dos propiedades, una que utiliza el comportamiento de carga diferida normal (que puede establecer una carga ansiosa para consultas específicas donde tiene sentido) y otra que siempre devuelve una relación dinámica.

class User(Base): 
    id = Column(Integer, primary_key=True) 
    name = Column(String, nullable=False, unique=True) 
    created_at = Colmn(DateTime, nullable=False, default=func.now()) 

class Post(Base): 
    id = Column(Integer, primary_key=True) 
    user_id = Column(Integer, ForeignKey(User.id), nullable=False) 
    user = relationship(User, backref=backref('posts')) 
    title = Column(String, nullable=False) 
    body = Column(Text, nullable=False) 
    created_at = Colmn(DateTime, nullable=False, default=func.now()) 

User.post_query = relationship(Post, lazy="dynamic") 
+0

en mi caso de forma predeterminada Quiero hacer 'joinedload', por excepción normal lazy loading. ¿Es posible? – noisy

+0

@noisy, es posible, pero eso no es muy similar a esta pregunta. [Por favor, pregunte uno nuevo] (http://stackoverflow.com/questions/ask). – SingleNegationElimination

+0

Tenga en cuenta que si utiliza múltiples relaciones como esta en una configuración de varios a muchos, necesita marcar una de las relaciones como 'pasivo_delete = verdadero', de lo contrario se lanza' StaleDataError' porque el ORM intenta eliminar elementos en el misma mesa a través de ambas relaciones. http://stackoverflow.com/a/17242712/1255482 – Josh

Cuestiones relacionadas