Supporting proxy models throughout Wagtail
See original GitHub issueIssue Summary
While there are a number of issues/PRs relating to support of proxy models in various parts of Wagtail (#1736, #4913, #1029, #4273, #3594), I feel that we’re missing a trick by only looking at the those issues in isolation. This issue aims to discuss the matter more generally, with an aim to establishing a clean, consistent approach that can be applied throughout the wider project.
Where are we now?
There are a good few places in Wagtail where using proxy models fails to work as expected. The exact details vary from place to place, but I feel they can all really be summarised as follows:
- Django creates
Permissionobjects for each proxy model, but they are associated with theContentTypefor the concrete model. - When we want to identify the
ContentTypefor a model, we tend to useContentType.objects.get_for_model()which, when provided with a proxy model, returns theContentTypefor the concrete model by default. ContentType.objects.get_for_model()supports afor_concrete_modeloption (which has a default value ofTrue), which can be used to retrieve a uniqueContentTypeobject for each proxy model instead of that of the concrete model. But,Permissionobjects for the proxy models remain associated with theContentTypeof the concrete model.- Because of all of the above, identifying the correct
ContentTypeandPermissionobjects for a proxy model (or worse, identifying the relevant model from aPermissionorContentTypeobject) becomes tricky.
Where do we want to be?
I think we can all agree that supporting proxy models is much simpler/cleaner when proxy models have their own ContentType, and model permissions are related to that ContentType. In fact, this is how Django intends for things to be from version 2.2
There’s a clear desire for proxy model support in Wagtail, and the changes in Django 2.2 will make that easier, but changing our code to benefit from those changes would leave a gap in proxy model support in earlier Django versions, which would be nice to fill somehow.
We want using proxy models in Wagtail to be simple for developers, but we don’t want to force wholesale data changes on to every project where Wagtail is installed, so there should at least be an ‘opt-in’ step.
How might we get there?
Below are the most up-to-date recommendations:
- Update Wagtail to use
for_concrete_model=Falseandfor_concrete_models=Falseoptions throughout, whereverContentType.objects.get_for_model()orContentType.objects.get_for_models()are used (respectively). - For Django versions < 2.2, we utilise Django’s
post_migratesignal to update proxy model permissions to be associated with their respectiveContentTypeobjects, making things consistent accross all supported Django versions. - The functionality in step 2 would be disabled by default, so as not to force the
Permissionchanges onto projects that utilise proxy models outside of Wagtail, and might not be planning to update to Django 2.2 anytime soon. Developers would opt-in by adding something likeWAGTAIL_UPDATE_PROXY_MODEL_PERMISSIONS = Trueto their project’s Django settings. - To make the changes reversible in Django < 2.2, a management command could be added, that would essentially do the opposite of the signal handler in step 2.
As always, looking forward to hearing other’s thoughts/suggestions on this 😃
Issue Analytics
- State:
- Created 5 years ago
- Comments:32 (25 by maintainers)

Top Related StackOverflow Question
@chosak Assuming we stick to our current release pattern, the next LTS will be around June/July, and by that time Django 2.2 will only be a couple of months old so it’s unlikely that we’ll be dropping support for <2.2 at that point. I’d say we’re most likely to drop Django <2.2 for the next LTS after that, in early 2020, by which time Django 2.1 will be out of support.
I’m a bit late to the party, but if Django 2.2 solves a big chunk of the problem, I think it would be reasonable to say “you need to use Django 2.2+ to benefit from those changes as well”, instead of trying to hack/bend Wagtail so it works with previous versions on Django as well (especially if we need to make sure to always use
for_concrete_modelwhich will be forgotten at some point and create bugs).That being said, I don’t know whether it would be easier for Wagtail to support Django newest additions while still being compatible with previous Django version or do what you are trying to accomplish here.