我有一个模型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}}。)
答案 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}}