2009-05-28 17 views
6

Acabo de introspectar un esquema bastante desagradable de una aplicación de CRM con sqlalchemy. Todas las tablas tienen una columna eliminada y quería filtrar automáticamente todas las entidades y relaciones marcadas como eliminadas. Esto es lo que ocurrió:¿La forma correcta de filtrar automáticamente las consultas de 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 

y se usa así:

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 es la clase que se asigna a la tabla de unión entre los correos electrónicos y los otros módulos que están relacionado con.

He aquí un ejemplo de un mapeador:

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 

Esto me da lo que quiero en que yo que cumplan con todos los contactos eliminados. También puede utilizar esto como el argumento query_class a dynamic_loader en mis mapeadores - Sin embargo ...

  1. ¿Hay una mejor manera de hacer esto, no estoy muy contento con hurgando con el funcionamiento interno de una clase compicated como Query como soy.
  2. ¿Alguien ha resuelto esto de una manera diferente que puedan compartir?

Respuesta

7

Puede asignar a una selección. De esta manera:

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

¡Muy bien, no sabía de eso! –

+0

Acabo de intentar hacer esto (en una tabla diferente) y no funcionó. Tengo: TypeError: el objeto 'Tabla' no es iterable ¿Alguna idea de por qué? –

+0

Malo, el primer parámetro para seleccionar es una lista de objetos similares a columnas/tabla, por lo que email_join debe estar en una lista. Lo arreglaré. –

0

lo consideraría ver si era posible crear puntos de vista de estas tablas que filtran los elementos eliminados, y entonces usted podría ser capaz de asignar directamente a la vista en lugar de la tabla subyacente, al menos para operaciones de consulta. ¡Sin embargo, nunca lo intenté yo mismo!

Cuestiones relacionadas