2016-09-12 61 views
0

考慮Django的example of using a "through" model到許多一對多的關係中指定額外的數據,僅改變Membership模型看起來像訂購Django的許多一對多通過模型

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包含由order有序組中首先Person實例一個查詢集,接着使殘存的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實例所屬的每個Group都有大量重複的Person實例。從評論

+0

混合以上羣體是不一樣的所有人只是搜索? 「那些屬於披頭士的人」和「不屬於披頭士的人」? – raratiru

+0

@raratiru你能給我一個你的意思嗎?我認爲第一個'qs1'的順序會是問題嗎? – fpghost

+0

我想要的是所有Person對象的集合,這些集合中的「beatles」按照它們的「order」字段排序,而那些不在beatles中的對象默認排序(name/id)。 – fpghost

回答

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對象的排序, 組中的那些「beatles」按照它們的「order」字段排序。

讓我們準備一個成員變量:

$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)進行排序。

在這裏,我得到所有其他成員,我通過組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)>]> 
+0

我不是在尋找兩個單一的查詢集。如果你檢查我的OP,我已經自己取得了兩個單獨的(第一個是按順序排列的披頭士的成員,第二個是所有按照名字排序的披頭士的人)。我需要的是一個單一的查詢集,它將這些事情與他們給定的命令結合起來。 – fpghost

+0

@fpghost我有 - 相應地更新了我的答案。 – raratiru