【问题标题】:Filtering "downstream" related objects in Django's ORM?在 Django 的 ORM 中过滤“下游”相关对象?
【发布时间】:2017-05-18 21:33:42
【问题描述】:

有没有办法过滤类中的相关对象。我不是在谈论按相关对象过滤,而是在类中过滤相关对象本身。也许一个例子会更好地说明:

假设我有以下模型:

class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.ForeignKey('Author', null=True)
    isbn = models.CharField('ISBN',max_length=13)
    genre = models.ManyToManyField(Genre)


class Genre(models.Model):
    name = models.CharField(max_length=200)
    ...

class Author(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    date_of_birth = models.DateField(null=True, blank=True)
    date_of_death = models.DateField('Died', null=True, blank=True)

我知道如何进行简单的过滤,例如获取特定类型的所有书籍:

books = Books.objects.filter(genre=1)

然后在视图中循环:

{% for book in books %}
  {{book.title}}
{% endfor %}

但是,有没有办法过滤查询集的相关对象?假设我有一个已经过滤的作者查询集,我只想列出他的特定类型的书:

如果我这样做:

{% for book in author.books_set.all %}
  {{book.title}}
{% endfor %}

我得到了他所有的书(正如我所期望和想要的那样)。

但是,有没有办法做这样的事情:

{% for book in author.books_set.filter(genre=1) %}
  {{book.title}}
{% endfor %}

所以我只得到相关对象的过滤列表?

我更喜欢在视图中或作为类方法执行此操作,因为我不喜欢在模板中混合逻辑。

即:

{% for book in author.books.filtered_genres %}
  {{book.title}}
{% endfor %}

但是,我似乎无法找出最好和最 Pythonic(或 djangonic :) )的方式来做到这一点。

我知道我可以自己在视图中“构建”一个数据结构,方法是遍历各种查询集并构建我想要的,但我希望保留已经定义的数据模型和关系。

对我要完成的工作有什么想法吗?或者我可以更好地详细说明我正在尝试做的事情吗?

谢谢!

【问题讨论】:

    标签: django django-models


    【解决方案1】:

    您可以在 Book 模型的查询集中应用或连接多个过滤器:

    books = Books.objects.filter(author='Bob', genre=1)
    

    books = Books.objects.filter(author='Bob').filter(genre=1)
    

    或者 - 如果你想查询相关对象 - 你可以使用prefetch_related 方法:

        author_genre_books = Author.objects.filter(author='Bob').prefetch_related(book_set__genre=1)
    

    【讨论】:

      【解决方案2】:

      @多鲁:

      我无法让它工作,遇到了一个错误

      auths = Author.objects.filter(author='Bob').prefetch_related(book__genre=1)  
      
      TypeError: prefetch_related() got an unexpected keyword argument 'book__genre'
      

      但是,你让我走上了正确的道路!!我在文档中找到了 Prefetch 方法。
      这就是我所做的并让它按照我的需要工作:

      auths = Author.objects.filter(author='Bob').prefetch_related(Prefetch('book_set', queryset=Book.objects.filter(genre=3), to_attr='filtered_books'))          
      

      然后在模板中使用以下内容:

      {% for book in author.filtered_books %}
        {{book.title}}
      {% endfor %}
      

      所以,感谢您让我走上正确的道路!

      【讨论】:

        猜你喜欢
        • 2018-11-18
        • 2022-06-12
        • 2017-07-02
        • 1970-01-01
        • 2010-09-20
        • 2019-02-14
        • 2012-11-29
        相关资源
        最近更新 更多