Django:将查询集与不同的过滤器组合在一起

时间:2015-02-09 23:46:11

标签: python django django-queryset

我有一个模型Book,其中包含模型Publisher的外键。

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) 1}}。)

1 个答案:

答案 0 :(得分:0)

使用complex lookups with Q objects.

可以实现
  

Q object (django.db.models.Q)是用于封装关键字参数集合的对象。

可以创建这些类似于查询集的filter方法,但然后使用set logic进行组合。

对于您的示例,为发布商任务创建一个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()) 部分来限制代码重复,如下所示:

{{1}}