question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

InheritanceManager doesn't work with Proxy Model

See original GitHub issue

I created an app to demonstrate this bug here https://github.com/chhantyal/mptt-test

Please see the models here https://github.com/chhantyal/mptt-test/blob/master/mptt_test/app/models.py

When I use select_subclasses(), it doesn’t give subclass object but superclass object (in this case ProxyPage object itself).

In [1]: from mptt_test.app.models import Blog, PageProxy

In [2]: Blog.objects.create(title='Title', quote='blog')
Out[2]: <Blog: Blog object>

In [3]: PageProxy.objects.all().select_subclasses()
Out[3]: [<PageProxy: PageProxy object>]

Issue Analytics

  • State:open
  • Created 8 years ago
  • Reactions:1
  • Comments:9

github_iconTop GitHub Comments

1reaction
Loraccommented, May 16, 2019

Same issue with:

  • Django 2.2
  • django-model-utils 3.1.2
0reactions
qwengercommented, Oct 18, 2020

Hi,

This hit me as well.

However, looking a bit more in detail into it, I feel like model-utils does the right thing / the best it can.

Proxy models in django only work on the Python level - there is no information stored about the proxy in the database (the table is shared with the base model). So when you query objects from a certain model (class), you get instances of that class. This is by design.

In that situation, model-utils has no way to know which model is “the right one” - because both are, there’s no difference on the db level! So it uses the non-proxy one in select_subclasses.

See also https://docs.djangoproject.com/en/3.1/topics/db/models/#querysets-still-return-the-model-that-was-requested.

(note: this is only my understanding of it, maybe I’m wrong)

EDIT:

To complete my point above, I would like to emphasize that proxy models in django are not subclasses in the MTI sense - they are other “views” of the same data. Accordingly, if you have a proxy model B to some model A, you can create instances of A or B and retrieve any of them later as A or B instance transparently.

In django, which model you want to retrieve instances of is explicit: from the model you take the manager of, from the definition of relation fields, from the arguments of select_related, etc.

In model-utils however the whole point of select_subclasses is to “guess” the return types, by scanning through possible subclasses in the db. So proxy models cannot be retrieved as they do not correspond to tables in the db on their own (only present as a row in django_content_type).

One case where model-utils could do better (or forbid this case altogether) is when one explicitly passes a proxy model as argument in select_subclasses:

class C(models.Model):
    objects = InheritanceManager()

class D(C):
    pass

class E(D):
    class Meta:
        proxy = True
>>> D().save() # or E().save(), doesn't make a difference

>>> C.objects.select_subclasses()
<InheritanceQuerySet [<D: D object (1)>]>
>>> C.objects.select_subclasses(D)
<InheritanceQuerySet [<D: D object (1)>]>
>>> D.objects.select_subclasses()
<InheritanceQuerySet [<D: D object (1)>]>
>>> E.objects.select_subclasses(E)
<InheritanceQuerySet [<E: E object (1)>]>
>>> C.objects.select_subclasses(E)
<InheritanceQuerySet [<D: D object (1)>]>
>>> D.objects.select_subclasses(E)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/home/matpi/.local/share/virtualenvs/tmp_django_mti/lib/python3.8/site-packages/model_utils/managers.py", line 219, in select_subclasses
    return self.get_queryset().select_subclasses(*subclasses)
  File "/home/matpi/.local/share/virtualenvs/tmp_django_mti/lib/python3.8/site-packages/model_utils/managers.py", line 70, in select_subclasses
    raise ValueError(
ValueError: '' is not in the discovered subclasses, tried: 

The first four calls to select_subclasses make sense. One could however argue that the last two should both succeed and return E instances.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Using InheritanceManager (django-model-utils) on proxy ...
I'm using InheritanceManager from django-model-utils to get the subclass of a given Django ... does it work when Specific is not a proxy?...
Read more >
#24762 (Proxy models with children which inherit from the ...
I've not worked with proxies much, and certainly not recently, ... model as the parent for auto-downcasting model instances (using it's InheritanceManager )....
Read more >
InheritanceManager - django-model-utils - Read the Docs
It allows queries on that base model to return heterogeneous results of the actual proper subtypes, without any additional queries.
Read more >
[Solved]-Polymorphism in Django models-django
This is not what Proxy models are intended for but I wouldn't recommend using ... When polymorphism works well it's fine, but when...
Read more >
QuerySets of various models
It also overcomes the third problem. We have distinct classes, which can have their own methods. We don't need to try to use...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found