Opened 3 years ago

Last modified 22 months ago

#19222 new Cleanup/optimization

Documentation for use_for_related_fields should clarify that it doesn't work for intermediate joins

Reported by: andrewbadr Owned by: nobody
Component: Documentation Version: 1.4
Severity: Normal Keywords:
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no


I have a custom Manager to filter out model instances with where the field deleted is True. I'm using an ORM query that looks like user1.page_set.filter(membership__user=user2). The option use_for_related_fields=True is set on the relevant manager.

My expectation is that Membership objects with the deleted flag set are not included in the query. Instead, they are being included.

The documentation for use_for_related_fields should should specify that it doesn't work in this case.

Change History (4)

comment:1 Changed 3 years ago by mattaustin

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Resolution set to needsinfo
  • Status changed from new to closed
  • Type changed from Uncategorized to Bug

Attempted to reproduce this, but require more info on model relationships.

comment:2 Changed 2 years ago by jedediah

class BagelManager(Manager):
    use_for_related_fields = True

    def get_query_set(self):
        return super(BagelManager, self).get_query_set().filter(deleted=False)

class Bagel(Model):
    deleted = BooleanField()

    objects = BagelManager()
    all_bagels = Manager()

    def __str__(self):
        return "deleted" if self.deleted else "active"

class Customer(Model):
    bagels = ManyToManyField(Bagel)
>>> Bagel.objects.create(deleted=False)
<Bagel: active>
>>> Bagel.objects.create(deleted=True)
<Bagel: deleted>
>>> Bagel.all_bagels.all()
[<Bagel: active>, <Bagel: deleted>]
>>> Bagel.objects.all()
[<Bagel: active>]
>>> Bagel.objects.filter(deleted=True)

Correct so far... deleted bagel is invisible through default manager

>>> c = Customer.objects.create()
>>> c.bagels.add(*Bagel.all_bagels.all())
>>> c.bagels.all()
[<Bagel: active>]
>>> c.bagels.filter(deleted=True)

Still good... deleted bagel is invisible to related fields

>>> Customer.objects.filter(bagels__deleted=True)
[<Customer: Customer object>]

Here's the problem. The query join sees the deleted bagel. I would expect queries through relations to see the same data as the relations themselves.

This should either be fixed or documented as a known limitation.

comment:3 Changed 2 years ago by jedediah

  • Resolution needsinfo deleted
  • Status changed from closed to new

comment:4 Changed 22 months ago by timo

  • Triage Stage changed from Unreviewed to Accepted
  • Type changed from Bug to Cleanup/optimization

I don't think this a behavior that's going to change, so documentation seems like the way to go. If you'd like to write a patch, I'll be happy to review it.

Note: See TracTickets for help on using tickets.
Back to Top