过滤"下游" Django的ORM中的相关对象?

时间:2017-05-18 21:33:42

标签: django django-models

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

说我有以下型号:

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 :))方法来做到这一点。

我知道我可以建造'通过循环遍历各种查询集并构建我想要的东西,我自己在视图中的数据结构,但我希望保留已定义的数据模型和关系。

对我想要完成的任何想法?或者我可以更好地阐述我想要做的事情吗?

谢谢!

2 个答案:

答案 0 :(得分:2)

您可以在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)

答案 1 :(得分:0)

@Doru:

我无法让这个工作,

出错了
auths = Author.objects.filter(author='Bob').prefetch_related(book__genre=1)  

TypeError: prefetch_related() got an unexpected keyword argument 'book__genre'

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

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 %}

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