Peewee ORM - 过滤具有多对多关系的结果

Peewee ORM - Filtering Result with Many-To-Many Relation

全部,

我正在尝试使用 Peewee 查询用户和地址系统。我试图过滤掉多对多关系。我取回了正确的对象,但是当我通过列表(查询)return 对象时,我没有删除不匹配的关系。例如,如果我想获取纽约 (NY) 状态为 4 的用户的所有地址,我将执行这样的查询:


设置:

class Address(Model):
    address_line_1 = CharField(null=True)
    address_line_2 = CharField(null=True)
    city = CharField(null=True)
    state_abbr = CharField(null=True, max_length=2)
    state = IntegerField(default=NEW_ID, choices=STATE_CHOICES)

class LicenseNumber(Model):
    number = CharField(unique=True, index=True)
    state = IntegerField(default=NEW_ID, choices=STATE_CHOICES)

class User(Model):
    license = ForeignKeyField(LicenseNumber, null=True)
    addresses = ManyToManyField(Address, related_name="users")
    state = IntegerField(default=NEW_ID, choices=STATE_CHOICES)

示例:

def get_filtered_users(...):
    # Get the through model for the many-to-many relationship
    UserAddresses = User.addresses.get_through_model()

    # Query users & license & addresses
    query = (User
             .select(User, Address, LicenseNumber)
             .join(UserAddresses)
             .join(Address)
             .switch(User) # Switch the context back to the user
             .join(LicenseNumber)
             .where(  # Filter out addresses that are not in NY & not state 4
                   (User.state == 4) & 
                   (Address.state_abbr << ['NY']) &
                   (Address.state == 4))
             .having(  # Also tried to ensure that I only get what we want 
                   (Address.state == 4) & 
                   (Address.state_abbr << ['NY'])))

    # Return the users
    return list(query)

当我查看对象视图 query.dict() 时,我可以查看 returned 的项目,它们是正确的。有没有办法 return 具有被过滤的关联关系的实例化用户对象?查看过滤后的记录时,我希望在执行查询时看到过滤掉的关系。


预期结果:

用户 1:

地址 1


实际结果:

用户 1:

地址 1

地址 2:


目标是使用用户对象并引用通过以下方式过滤的地址:

# Return the users & their filtered information
return list(query)

在迭代记录实例时,我是否遗漏了一些东西来过滤掉关系中的记录?任何帮助都会很棒

通过仔细搜索和阅读文档,我花了一段时间才弄明白。

解决方案是使用 PeeWee 提供的 aggregate_rows 功能。此功能有助于防止 N+1 查询(您需要在其中获取相关记录)。

本质上,这将 select SELECT 语句中定义的关系。因为我们在寻找地址的状态时正在建立多对多关系,所以我们需要涉及三个 table。在这种情况下,它将是 Users、UserAddresses(通过 table)和 Addresses,它们都在 select 语句中。在查询结束时,我们需要调用 aggregate_rows() 来执行提取和组合。


代码应如下所示:

def get_filtered_users(...):
    # Get the through model for the many-to-many relationship
    UserAddresses = User.addresses.get_through_model()

    # Query users & license & addresses
    query = (User
         .select(User, Address, UserAddresses, LicenseNumber)
         .join(UserAddresses)
         .join(Address)
         .switch(User) # Switch the context back to the user
         .join(LicenseNumber)
         .where(  # Filter out addresses that are not in NY & not state 4
               (User.state == 4) & 
               (Address.state_abbr << ['NY']) &
               (Address.state == 4))
         .aggregate_rows())

    # Return the users
    return list(query)

我们现在收到状态的预期结果:4