Python SQLAlchemy属性映射的集合和缺少的值?

Python SQLAlchemy属性映射的集合和缺少的值?,python,sqlalchemy,Python,Sqlalchemy,使用以下映射集合设置,使用字典语法在另一个表中映射具有任意数量属性的人员进行访问: class FormField(Model): id = Column(Integer, primary_key=True) person_id = Column(Integer, ForeignKey('person.id'), nullable=False) keyword = Column(String(255)) payload = Column(Text) class

使用以下映射集合设置,使用字典语法在另一个表中映射具有任意数量属性的人员进行访问:

class FormField(Model):
    id = Column(Integer, primary_key=True)
    person_id = Column(Integer, ForeignKey('person.id'), nullable=False)
    keyword = Column(String(255))
    payload = Column(Text)


class Person(Model):
    id = Column(Integer, primary_key=True)
    name = Column(String(255))
    fields = relationship("FormField",
              collection_class=attribute_mapped_collection('keyword'),
              cascade="all, delete-orphan")
正常使用方法另请参见文档:

搜索具有特定属性值的人也非常简单。然而,问题是,如何搜索根本没有属性的人,尤其是作为更复杂查询的一部分的人

一种方法可能是始终创建所有属性并将NULL放入(比如)有效负载中,但有可能高效地搜索完全缺失的属性吗?例如,查询是否应该挖掘出属性a有值a、属性b有值b和缺少属性c的人员

db.session.query(Person).join(FormField).join(FormField_alias)
    .filter(FormField.keyword == "a", FormField.payload == "A")
    .filter(FormField_alias.keyword == "b", FormField_alias.payload == "B")
    # ???
    .all()
我想,这并不像增加一个过滤器那么简单。但是接下来呢?

您可以使用一组而不是内部联接:

In [48]: session.query(Person).\
    ...:     filter(Person.fields.any(and_(FormField.keyword == 'a',
    ...:                                   FormField.payload == 'A')),
    ...:            Person.fields.any(and_(FormField.keyword == 'b',
    ...:                                   FormField.payload == 'B')),
    ...:            not_(Person.fields.any(FormField.keyword == 'c'))).\
    ...:     all()

例如,在Postgresql中,EXISTS和NOT EXISTS生成半联接和反联接,如果索引正确,这些联接应该非常有效。

所以我想我需要将person\u id添加到和的内部。不,这是从关系中暗示出来的。
In [48]: session.query(Person).\
    ...:     filter(Person.fields.any(and_(FormField.keyword == 'a',
    ...:                                   FormField.payload == 'A')),
    ...:            Person.fields.any(and_(FormField.keyword == 'b',
    ...:                                   FormField.payload == 'B')),
    ...:            not_(Person.fields.any(FormField.keyword == 'c'))).\
    ...:     all()