Django overrides double underscore search behavior in queries

My main question is: is there a way to change the behavior of a linked search, for example MyModel.objects.filter(relationship__field="value")?

Consider this setting. I have a one-to-many relationship with a custom dispatcher that filters books withactive=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()

And create some data:

jim = Author.objects.create(name="Jim")
ulysses = Book.objects.create(title="Ulysses", author=jim, active=True)
finnegans = Book.objects.create(title="Finnegan Wake", author=jim, active=False)

bill = Author.objects.create(name="Bill")
hamlet = Book.objects.create(title="Hamlet", author=bill, active=False)

In fact, I never want to deal with inactive books. Here are some queries to test different scenarios.

>>> 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 only book has active=False.
# I want the queryset to return no results.

Is there any way to change the search behavior books__*to enable an additional filter in active?

+4
source share
3 answers

:

Django "" (.. choice.poll), . , Django , (, , ) .

(django.db.models.Manager) , Django , , use_for_related_fields .

:

class ActiveOnly(models.Manager):

    use_for_related_fields = True

    def get_queryset(self):
        return super(ActiveOnly, self).get_queryset().filter(active=True)
+1

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) isnt , Django, Meta.base_manager_name.

, BaseManager, !

+1

: , QuerySet, , books__active=True .

github , , - . 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.

.

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
0

Source: https://habr.com/ru/post/1648446/


All Articles