SQLAlchemy查询的自动过滤正确方法是什么?

8 投票
2 回答
4698 浏览
提问于 2025-04-15 11:53

我刚刚用sqlalchemy分析了一个来自CRM应用的复杂数据库结构。所有的表都有一个“deleted”列,我想自动过滤掉那些被标记为删除的记录和关系。于是我想出了以下方法:


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

这个方法的使用方式如下:

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('someone@some.com')

EmailInfo是一个类,它对应着一个连接表,这个表连接了电子邮件和它们相关的其他模块。

下面是一个映射器的例子:

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

这样做的结果是,我成功过滤掉了所有被删除的联系人。我还可以把这个作为动态加载器中的query_class参数使用在我的映射器里。不过……

  1. 有没有更好的方法?我对直接操作像Query这样复杂的类并不太满意。
  2. 有没有人用其他方法解决过这个问题,可以分享一下吗?

2 个回答

0

我建议可以看看是否能为这些表创建一些视图,这些视图可以过滤掉被删除的内容。这样的话,你就可以直接使用这个视图来进行查询,而不是直接操作底层的表。至少在查询的时候可以这样做。不过我自己从来没有尝试过!

7

你可以把它映射到一个选择框。就像这样:

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

撰写回答