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
Permission
objects for each proxy model, but they are associated with theContentType
for the concrete model. - When we want to identify the
ContentType
for a model, we tend to useContentType.objects.get_for_model()
which, when provided with a proxy model, returns theContentType
for the concrete model by default. ContentType.objects.get_for_model()
supports afor_concrete_model
option (which has a default value ofTrue
), which can be used to retrieve a uniqueContentType
object for each proxy model instead of that of the concrete model. But,Permission
objects for the proxy models remain associated with theContentType
of the concrete model.- Because of all of the above, identifying the correct
ContentType
andPermission
objects for a proxy model (or worse, identifying the relevant model from aPermission
orContentType
object) 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=False
andfor_concrete_models=False
options throughout, whereverContentType.objects.get_for_model()
orContentType.objects.get_for_models()
are used (respectively). - For Django versions < 2.2, we utilise Django’s
post_migrate
signal to update proxy model permissions to be associated with their respectiveContentType
objects, making things consistent accross all supported Django versions. - The functionality in step 2 would be disabled by default, so as not to force the
Permission
changes 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 = True
to 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 GitHub Comments
@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_model
which 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.