考虑到Django的example of using a "through" model指定多对多关系的额外数据,只将Membership
模型更改为
class Membership(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
order = models.PositiveIntegerField()
class Meta:
ordering = ('order', )
这样存储的额外数据就是一个订单参数,用于指定Person
中Group
的顺序。
我的目标是获取给定Group
的查询集,该查询集包含由Person
排序的组中的所有order
个实例,其次是剩余的Person
个实例(不是在name
订购的小组中。
我可以使用两个查询集来完成此操作,例如
# Get all beatles members ordered by the through model
qs1 = beatles.members.all().order_by('membership__order')
# Get the remaining Persons (those not in the beatles) ordered by name
qs2 = Person.objects.exclude(id__in=qs1).order_by('name')
这些查询集似乎包含预期的Person实例。但是,我需要两者的组合查询集,而不仅仅是列表或一些itertools“链”对象,因为我想提供它来初始化需要查询集实例的表单字段。
我试过
result_qs = qs1 | qs2
但是我发现result_qs
可以包含重复项(即使我认为联合应该删除重复项?为什么有重复项?有时甚至可能是qs1和qs2不重叠的情况!!)。
如果我这样做
result_qs = (qs1 | qs2).distinct()
它看起来似乎有效,但如果我正在做的事情总能发挥作用,我很怀疑,并且是实现这一目标的好方法。
注意,执行Person.objects.all().order_by('membership__order')
会导致Person实例所属的每个Person
有大量重复Group
个实例。
答案 0 :(得分:0)
从评论中更新:
正如我在问题的第一个评论中所指出的那样,将两个查询混合在一起并对其进行部分排序就像要求一个"两个分层的"以下查询的order_by
属性:
Membership.objects.all()
我不确定目前是否支持此功能。
这是我们在名为Beatles
的虚构应用程序中的模型:
甲壳虫/ models.py:
from django.db import models
# Create your models here.
class Person(models.Model):
name = models.CharField(max_length=128)
def __str__(self): # __unicode__ on Python 2
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __str__(self): # __unicode__ on Python 2
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
order = models.PositiveIntegerField()
def __str__(self):
return '{0}: {1} (order {2})'.format(self.group, self.person, self.order)
class Meta:
ordering = ('order', )
我想要的是所有订购的Person对象的集合 在集团"披头士乐队"按他们的订单排序"订购"字段。
让我们准备一个会员资格变量:
$manage.py shell
>>>from beatles.models import Membership
>>>memberships = Membership.objects.all().select_related('person', 'group')
现在我们将根据需要操纵成员资格变量。让我们找到所有披头士乐队成员作为模型class Meta
要求订购:
>>>beatles_membership_results = memberships.filter(group__name='Beatles')
>>>beatles_membership_results
<QuerySet [<Membership: Beatles: Ringo (order 1)>, <Membership: Beatles: Paul (order 2)>]>
,默认情况下订购那些不在披头士乐队中的人 (名称/编号)。
在这里,我获得所有其他成员,并按组ID订购。在结果中你会发现乔治两次,因为他属于两个不同的群体。
>>>general_membership_results = memberships.exclude(group__name='Beatles').order_by('group__id')
>>>general_membership_results
<QuerySet [<Membership: Daring Flowers: George (order 3)>, <Membership: Misty November: Lulu (order 4)>, <Membership: Daring Flowers: Terrenton (order 5)>, <Membership: Misty November: George (order 6)>]>
您可以按名称订购:
>>>general_membership_results = memberships.exclude(group__name='Beatles').order_by('person__name')
>>>general_membership_results
<QuerySet [<Membership: Daring Flowers: George (order 3)>, <Membership: Misty November: George (order 6)>, <Membership: Misty November: Lulu (order 4)>, <Membership: Daring Flowers: Terrenton (order 5)>]>