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

时间:2017-05-22 18:58:29

标签: python peewee

所有

我正在尝试使用Peewee查询用户和地址系统。我试图过滤掉多对多的关系。我找回了正确的对象,但是当我通过list(query)返回对象时,我没有删除不匹配的关系。例如,如果我想获取纽约(纽约州)状态为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()时,我可以查看返回的项目,它们是正确的。有没有办法返回具有过滤关联关系的实例化User对象?查看过滤后的记录时,我希望在执行查询时看到过滤掉的关系。

预期结果:

用户1:

地址1

  • 州:4
  • Abbr:NY

实际结果:

用户1:

地址1

  • 州:4
  • Abbr:NY

地址2:

  • 国家:2
  • Abbr:NY

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

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

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

1 个答案:

答案 0 :(得分:1)

这让我花了一些时间来仔细搜索和阅读文档。

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

本质上,这将选择SELECT语句中定义的关系。因为我们在查找地址状态时正在进行多对多关系,所以我们需要涉及三个表。在这种情况下,它将是select语句中的Users,UserAddresses(直通表)和Addresses all。最后,我们需要调用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