2014-01-21 66 views
0

我有以下的Django模型(這裏大大簡化):訂購Django的查詢集由兩個串聯的M2M領域

class Author: 
    name = models.TextField() 

class Editor: 
    name = model.TextField() 

class Publication: 
    authors = models.ManyToManyField(Author) 
    editors = models.ManyToManyField(Editor) 

的出版物可以有要麼作者編輯器,但不能同時使用。我想按照字母順序排列作者和編輯統一的出版物清單。換句話說,我想通過一個虛擬領域來訂購,我們稱之爲creators,這是作者和編輯的連接。

查詢:

Publication.objects.all().order_by('authors__name', 'editors__name') 

...將聚集在一起是沒有作者,並在該組中的排序按編輯出版物,這不是我想要的。實際上,它應該使用任何作者或編輯可用於發佈和排序。

這種排序必須發生在數據庫級,結果集可能很大。

回答

0

一種方法是創建一個名爲creators方法:

class Publication: 
    authors = models.ManyToManyField(Author) 
    editors = models.ManyToManyField(Editor) 

    def creators(self): 
     return self.authors + self.creators 

但缺點是,你不能在數據庫級進行排序,但在Python層面:

sorted(Publication.objects.all(), key=lambda k: " ".join(p.name for p in k)) 
+0

結果集很大,所以這個排序必須發生在數據庫級別。我已經添加了這個作爲我的問題的一個筆記。 :) –

+0

爲什麼不在保存時添加一個具有排序列表名稱的附加列?無論如何,您必須在執行連接時對名稱進行排序。 – arocks

+0

M2M領域記得嗎?無需調用save(),M2M關係列表就可以更改。 –

0

我可以把這個扔掉?您可能需要AuthorsEditors繼承Contributors。因爲這兩個模型都有類似姓名,地址等。

+0

這是一個嚴格簡化的例子。這種繼承不會改變這個問題,只會爲示例添加不必要的額外行。 –

+0

(也就是說,實際上將兩個字段合併爲一個將是一個解決方案,但在這種情況下由於其他限制而不適合。:) –

+0

嗯。然後你可以用原始的sql來完成。但這是最後的手段,不是。 –

0

要按字段中定義的值進行排序,您需要創建一個組合字段,可以在模型級別訪問QuerySet ,使用自定義的Aggregate或使用額外的子句。

如果你不需要是完全不可知的DB額外的可能是最容易實現的:

qs = Publication.objects.extra({ 
    select={'contributor': "COALESCE(author.name,editor.name)"} 
}) 
qs.extra(order_by = ['contributor']) 

https://docs.djangoproject.com/en/1.6/ref/models/querysets/#django.db.models.query.QuerySet.extra

如果您確實需要DB獨立的,你應該看看使用一個concat作爲聚合的實現。例如,

http://harkablog.com/inside-the-django-orm-aggregates.html

+0

我希望能夠使用類似'extra()'的建議,但我無法使其與我的M2M領域一起工作。請記住,每個出版物可能有多位作者,編輯也是如此。有任何想法嗎? –