2010-10-29 7 views
4

que je fais une jointure comme ça dans SQLAlchemy de annoter de Django():SQLAlchemy équivalent à la méthode

items = Item.query\ 
    .outerjoin((ItemInfo, ItemInfo.item_id==Item.id)) 
items.add_columns(ItemInfo.count) 

Cela provoque SQLAlchemy pour revenir tuples:

>>> items.first() 
(<Item ...>, 2) 

Je préfère de beaucoup si la valeur « count » serait plutôt retourné comme un attribut de l'élément, à savoir que je veux faire:

>>> items.first().count 
2 

est-ce soutien ed?

Répondre

6

En fait, "items.first(). Count" fonctionnerait, puisque le tuple que vous récupérez est un tuple nommé ... mais devinant que vous ne voulez pas voir items.first(). Item.foo.

La deuxième façon, vous pouvez le faire serait juste pour exécuter le résultat de votre requête() par une fonction qui construit le genre de résultat que vous voulez:

def process(q): 
    for item, count in q: 
     item.count = count 
     yield count 

modifier: est une généralisée ici version:

from sqlalchemy.orm.query import Query 

class AnnotateQuery(Query): 
    _annotations =() 

    def annotate(self, key, expr): 
     q = self.add_column(expr) 
     q._annotations = self._annotations + (key,) 
     return q 

    def __iter__(self): 
     if not self._annotations: 
      return super(AnnotateQuery, self).__iter__() 
     else: 
      for row in super(AnnotateQuery, self): 
       item, remaining = row[0], row[1:] 
       for i, key in enumerate(self._annotations): 
        setattr(item, key, remaining[i]) 
       yield item 


# session usage: 

Session = sessionmaker(query_cls=AnnotateQuery) 

# query usage: 
q = Session.query(Item).outerjoin(...).annotate('count', Item.count) 

La troisième, est que vous modifiez la classe Item pour prendre en charge cette fonction. Vous utiliseriez column_property() pour appliquer une sous-requête à votre classe: http://www.sqlalchemy.org/docs/orm/mapper_config.html#sql-expressions-as-mapped-attributes. Si vous souhaitez que le chargement de l'attribut soit conditionnel, vous devez utiliser différé: http://www.sqlalchemy.org/docs/orm/mapper_config.html#deferred-column-loading.

+0

Merci. La troisième option semble très cool, mais je ne veux probablement pas promouvoir cette requête locale spécifique à un niveau global-Model. Cela peut être utile si SQLAlchemy prend en charge quelque chose comme (2) comme méthode intégrée pour renvoyer le résultat. – miracle2k

+0

mmm c'est un peu trop arbitraire comme un builtin, j'ai ajouté une recette généralisée à ma réponse ci-dessus que vous pouvez syntoniser à vos goûts. – zzzeek

Questions connexes