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



All,

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


预期成果:

用户 1:

地址 1

  • 州: 4
  • 缩略语:纽约

实际结果:

用户 1:

地址 1

  • 州: 4
  • 缩略语:纽约

地址 2:

  • 州: 2
  • 缩略语:纽约

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

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

在迭代记录实例时,我是否缺少筛选出关系中的记录的内容?任何帮助都会很棒

这花了我一段时间才通过非常仔细地搜索和阅读文档来弄清楚。

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

实质上,这将选择 SELECT 语句中定义的关系。由于我们在查找地址状态时要执行多对多关系,因此我们需要所涉及的三个表。在本例中,它将是 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

最新更新