Opened 5 years ago

Closed 5 years ago

#30721 closed Bug (invalid)

Implicit related objects filtration because of the set Manager.

Reported by: ApaDoctor Owned by: nobody
Component: Database layer (models, ORM) Version: dev
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

When abstract model is defined with objects manager.
And its child-model defines another manager - RelatedManager uses defined manager instead of objects.

class SomeAbstractModel(models.Model):
    class Meta:
        abstract = True

    objects = models.Manager()


class CustomManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(some_field=True)


class SomeThing(SomeAbstractModel):
    some_field = models.BooleanField()

    parent = models.ForeignKey(
        "SomeThing", related_name="children", on_delete=models.SET_NULL, null=True
    )

    custom_objects = CustomManager()

So we have abstract model, which defines objects manager for the model.

Our model uses that abstract class.

I created some objects:

SomeThing(some_field=True).save()
SomeThing.objects.bulk_create([SomeThing(some_field=bool(x%2), parent_id=1) for x in range(0,6)])

After i reloaded shell i tried to make queries:

>>> x = SomeThing.objects.get(id=1)
>>> x.children.count()
3
>>>SomeThing.objects.filter(parent_id=1).count()
6

Generated raw SQL for first query is:

SELECT COUNT(*) AS "__count" FROM "sapp_something" WHERE ("sapp_something"."some_field" = true AND "some_something"."parent_id" = 1)

Change History (1)

comment:1 by Mariusz Felisiak, 5 years ago

Component: UncategorizedDatabase layer (models, ORM)
Resolution: invalid
Status: newclosed
Version: 2.2master

Thanks for the report, IMO everything works properly, let's analyze this step by step.

You inherited from SomeAbstractModel with a manager and define a custom_manager in SomeThing. custom_manager is a default manager for SomeThing that's why it's used by related manager (e.g. x.children). In the same time SomeThing inherited objects manager from SomeAbstractModel (it's no longer a default manager provided by Django, see manager-names) so when you call it explicit e.g. SomeThing.objects.filter(parent_id=1).count() it returns all rows, without an extra filter (see also custom-managers-and-model-inheritance and using-a-custom-reverse-manager).

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