pythondjangoforeign-keys

Why does my Django models.Manager return all objects on a relationship?


I don't particularly understand what's going on here, but it seems that super().get_queryset() doesn't do what I think it does?

I have 1:N relationship, and the default FK reverse lookup works:

>>> for thing in this.thing_set.all():
...   print(thing.this)

Each one of these is This.

However, with my customized:

>>> for thing in this.thing_set.by_date():
...   print(thing.this)

Will produced This and `That*

class ThingByDateManager(models.Manager):
    def by_date(self):
        return super().get_queryset().order_by("start_time")

That's all there is.

class This(models.Model):
    name = models.CharField(max_length=255, primary_key=True)

class Thing(models.Model):
    start_time = models.DateTimeFiled()
    name = models.CharField(max_length=255)
    this = models.ForeignKey(This, on_delete=models.CASCADE)

    objects = ThingByDateManager()

(might not have those models perfectly written, but I'm hoping it's just something silly with the queryset or something)

Why doesn't this correctly filter my objects by this, instead returning all of the Things?


Solution

  • You don't override the get_queryset(), so super().get_queryset() will not look for the QuerySet of the first item in the method resolution order, but further down.

    This is important, since such related manager subclasses the existing one. Indeed, as the source code shows, it overrides the get_queryset() method to automatically filter.

    You thus should call self.get_queryset():

    class ThingByDateManager(models.Manager):
        def by_date(self):
            return self.get_queryset().order_by("start_time")
    

    as a general rule of thumb, it is strange to call super().bar() in a method where you define foo (not bar). While there are some cases where that is useful, usually you call the latest version of the method, and only use the previous one to "patch" it in a new version of that method.