【问题标题】:Django: Combining querysets with different filtersDjango:将查询集与不同的过滤器结合起来
【发布时间】:2015-04-09 21:28:14
【问题描述】:

我有一个模型 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))

但我希望能够将这两者组合成一个返回单个查询集的方法,从而允许我通过任务属性进一步过滤它(例如允许我执行 Publisher.objects.first().get_all_tasks().filter(complete=False)get_all_tasks() 方法。 )

【问题讨论】:

    标签: python django django-queryset


    【解决方案1】:

    这可以使用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())
    

    【讨论】:

      猜你喜欢
      • 2017-04-06
      • 2022-11-08
      • 1970-01-01
      • 2016-06-09
      • 2019-01-14
      • 2016-04-13
      • 2011-10-19
      • 2019-07-29
      • 1970-01-01
      相关资源
      最近更新 更多