2015-02-09 63 views
0

我有一個模型Book與一個外鍵來模型PublisherDjango:將查詢集合與不同的過濾器

class Publisher(models.Model): 
    ... 

class Book(models.Model): 
    publisher = models.ForeignKey(Publisher) 
    ... 

在一個單獨的應用程序,我有一個模型Task可以有一個通用外鍵的任何其他模型。

class Task(models.Model): 
    content_type = models.ForeignKey(ContentType) 
    object_pk = models.PositiveIntegerField() 
    content_object = generic.GenericForeignKey('content_type', 'object_pk') 
    complete = models.BooleanField(default=False) 
    ... 

我希望能夠以一個方法添加到Publisher模型,返回與它或任何出版商的圖書相關的所有任務。我可以單獨做他們:

class Publisher(models.Model): 
    ... 

    def get_tasks(self): 
     return Task.objects.filter(content_type=ContentType.objects.get_for_model(self), object_pk=self.pk) 

    def get_book_tasks(self): 
     return Task.objects.filter(content_type=ContentType.objects.get_for_model(Book), object_pk__in=self.related_books.values_list('pk', flat=True)) 

但我希望能夠到這兩個的組合爲返回單個查詢集的方法,讓我的任務屬性(如get_all_tasks()方法將進一步過濾它讓我做Publisher.objects.first().get_all_tasks().filter(complete=False)

回答

0

這是可能的使用complex lookups with Q objects.

一個Q object (django.db.models.Q)是用於封裝的關鍵字參數集合的對象。

這些可以創建類似於查詢集上的filter方法,但是隨後使用集合邏輯進行組合。

對於你的榜樣,創建一個Q爲出版商的任務,而另一個爲這本書的任務,並結合(|)他們,就像這樣:

from django.db.models import Q 
class Publisher(models.Model): 
    ... 

    def get_all_tasks(self): 
     publisher_tasks = Q(
      content_type=ContentType.objects.get_for_model(self), 
      object_pk=self.pk) 
     book_tasks = Q(
      content_type=ContentType.objects.get_for_model(Book), 
      object_pk__in=self.related_books.values_list('pk', flat=True)) 
     return Task.objects.filter(publisher_tasks | book_tasks) 

你甚至可以通過拉動Q部分限制代碼重複像這樣:

class Publisher(models.Model): 
    ... 

    def publisher_task_query(self): 
     return Q(
      content_type=ContentType.objects.get_for_model(self), 
      object_pk=self.pk) 

    def book_task_query(self): 
     return Q(
      content_type=ContentType.objects.get_for_model(Book), 
      object_pk__in=self.related_books.values_list('pk', flat=True)) 

    def get_tasks(self): 
     return Task.objects.filter(self.publisher_task_query()) 

    def get_book_tasks(self): 
     return Task.objects.filter(self.book_task_query()) 

    def get_all_tasks(self): 
     return Task.objects.filter(self.publisher_task_query() | self.book_task_query())