我的主要问题:有没有办法改变相关查找的行为,例如MyModel.objects.filter(relationship__field="value")
?
考虑这个设置。我与自定义管理器建立了一对多关系,该管理器使用active=False
from django.db import models
class ActiveOnly(models.Manager):
use_for_related_fields = True
def get_queryset(self):
return super(ActiveOnly, self).get_queryset().filter(active=True)
class Author(models.Model):
name = models.TextField()
class Book(models.Model):
active = models.BooleanField()
author = models.ForeignKey(Author, related_name="books")
title = models.TextField()
objects = ActiveOnly()
让我们创建一些数据:
jim = Author.objects.create(name="Jim")
ulysses = Book.objects.create(title="Ulysses", author=jim, active=True)
finnegans = Book.objects.create(title="Finnegan's Wake", author=jim, active=False)
bill = Author.objects.create(name="Bill")
hamlet = Book.objects.create(title="Hamlet", author=bill, active=False)
基本上,我从不想要处理非活动的书籍。以下是一些测试各种场景的查询。
>>> Book.objects.all().count() # expecting the 1 active book: good
1
>>> jim.books.all() # also expecting only 1: good
1
>>> Author.objects.filter(books__title="Hamlet").first().name
u'Bill'
# ^ this is what I don't want to see, because bill's only book has active=False.
# I want the queryset to return no results.
是否有任何方式更改books__*
查询的行为以在active
上添加其他过滤器?
答案 0 :(得分:2)
在Django 1.10中,不推荐使用Manager.use_for_related_fields
,而是赞成在模型上设置Meta.base_manager_name
。有关详细信息,请参阅更新的文档:
<强> Model._base_manager 强>
使用管理员进行相关对象访问
默认情况下,Django使用
Model._base_manager
管理器的实例 访问相关对象时的类(即choice.poll
),而不是 关于相关对象的_default_manager
。这是因为Django需要能够检索相关对象,否则即使它也是如此 被默认管理员过滤掉(因而无法访问)。如果普通的基本经理类(
django.db.models.Manager
)不是 适合你的情况,你可以告诉Django哪个班级 通过设置Meta.base_manager_name
来使用。
警告,而不是排除BaseManager中的对象仍然存在!
答案 1 :(得分:1)
默认情况下,Django在访问相关对象(即choice.poll)时使用“普通”管理器类的实例,而不是相关对象的默认管理器。这是因为Django需要能够检索相关对象,即使它被默认管理器过滤掉(因此也是不可访问的)。
如果普通的普通管理器类(django.db.models.Manager)不适合您的情况,可以通过在manager类上设置use_for_related_fields属性,强制Django使用与模型的默认管理器相同的类。
因此您需要将经理更改为:
class ActiveOnly(models.Manager):
use_for_related_fields = True
def get_queryset(self):
return super(ActiveOnly, self).get_queryset().filter(active=True)
答案 2 :(得分:0)
编辑:我不确定您是否可以在某处覆盖QuerySet类来获取此功能,我唯一的建议是将books__active=True
添加到您的查询中。
我已经将代码添加到github repo中,并且测试说明了如果有人想要将其用于旋转的问题。 https://github.com/alecklandgraf/NonDeletableDjangoModel
原帖:
我认为您可能需要在default_manager
模型中设置Book
,我会添加第二个模型管理器来查询不活动的图书。
class Book(models.Model):
active = models.BooleanField()
author = models.ForeignKey(Author, related_name="books")
title = models.TextField()
objects = ActiveOnly()
# try adding the following...
default_manager = ActiveOnly()
inactive_objects = models.Manager()
我重建了你的例子,发现它与Django 1.8和1.9相同。有趣的是您已经说明的创建的查询。您可以在"active" = True
查询的WHERE
子句中看到添加的Book
,但不会在Author
查询中看到。{/ p>
我会在这方面吃一段时间。
In [1]: Book.objects.filter(title="Hamlet")
Out[1]: []
In [2]: Author.objects.filter(books__title="Hamlet")
Out[2]: [<Author: Bill>]
In [3]: print Book.objects.filter(title="Hamlet").query
SELECT "library_book"."id", "library_book"."active", "library_book"."author_id", "library_book"."title" FROM "library_book" WHERE ("library_book"."active" = True AND "library_book"."title" = Hamlet)
In [4]: print Author.objects.filter(books__title="Hamlet").query
SELECT "library_author"."id", "library_author"."name" FROM "library_author" INNER JOIN "library_book" ON ("library_author"."id" = "library_book"."author_id") WHERE "library_book"."title" = Hamlet