2009-05-28 9 views
6

Ho appena introspettato uno schema piuttosto sgradevole da un'app CRM con sqlalchemy. Tutte le tabelle hanno una colonna cancellata e volevo filtrare automaticamente tutte le entità e le relazioni contrassegnate come cancellate. Ecco quello che mi si avvicinò con:Il modo giusto per filtrare automaticamente le query SQLAlchemy?


class CustomizableQuery(Query): 
    """An overridden sqlalchemy.orm.query.Query to filter entities 

    Filters itself by BinaryExpressions 
    found in :attr:`CONDITIONS` 
    """ 

    CONDITIONS = [] 

    def __init__(self, mapper, session=None): 
     super(CustomizableQuery, self).__init__(mapper, session) 
     for cond in self.CONDITIONS: 
      self._add_criterion(cond) 

    def _add_criterion(self, criterion): 
     criterion = self._adapt_clause(criterion, False, True) 
     if self._criterion is not None: 
      self._criterion = self._criterion & criterion 
     else: 
      self._criterion = criterion 

ed è utilizzato in questo modo:

class UndeletedContactQuery(CustomizableQuery): 
    CONDITIONS = [contacts.c.deleted != True] 

    def by_email(self, email_address): 
     return EmailInfo.query.by_module_and_address('Contacts', email_address).contact 

    def by_username(self, uname): 
     return self.filter_by(twod_username_c=uname).one() 

class Contact(object): 
    query = session.query_property(UndeletedContactQuery) 

Contact.query.by_email('[email protected]') 

EmailInfo è la classe che ha mappato alla tabella di raccordo tra e-mail e gli altri moduli che sono collegato a.

Ecco un esempio di un mapper:

contacts_map = mapper(Contact, join(contacts, contacts_cstm), { 
    '_emails': dynamic_loader(EmailInfo, 
           foreign_keys=[email_join.c.bean_id], 
           primaryjoin=contacts.c.id==email_join.c.bean_id, 
           query_class=EmailInfoQuery), 
    }) 

class EmailInfoQuery(CustomizableQuery): 

    CONDITIONS = [email_join.c.deleted != True] 
    # More methods here 

Questo mi dà quello che voglio in che ho filtrato tutti i contatti eliminati. Posso anche usare questo come argomento query_class a dynamic_loader nei miei mapper - Tuttavia ...

  1. c'è un modo migliore per fare questo, io non sono molto contento di frugare con la struttura interna di una classe compicated come Query come sono.
  2. Qualcuno ha risolto questo in un modo diverso che possono condividere?

risposta

7

È possibile eseguire la mappatura a una selezione. Come questo:

mapper(EmailInfo, select([email_join], email_join.c.deleted == False)) 
+0

Molto bello, non lo sapevo! –

+0

Ho appena provato a farlo (su una tabella diversa) e non ha funzionato. Ho ricevuto: TypeError: l'oggetto 'Table' non è iterable Qualche idea sul perché? –

+0

Il mio male, il primo parametro da selezionare è un elenco di colonne/oggetti di tipo tabella, quindi email_join dovrebbe essere in un elenco. Lo aggiusterò. –

0

che avevo in considerazione vedere se era possibile creare viste di queste tabelle che filtrano gli elementi eliminati, e allora si potrebbe essere in grado di mappare direttamente a quella vista al posto della tabella sottostante, almeno per le operazioni di interrogazione. Comunque non l'ho mai provato io!