New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] Proxy page models #1736
[WIP] Proxy page models #1736
Conversation
@@ -242,6 +242,11 @@ def specific(self): | |||
return self.get_queryset().specific() | |||
|
|||
|
|||
class ProxyPageManager(PageManager): | |||
def get_queryset(self): | |||
return super().get_queryset().type(self.model) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Calling .type(self.model)
is not enough here because that will return all the objects for the concrete model. This does work however:
return super(ProxyPageManager, self).get_queryset().filter(content_type=ContentType.objects.get_for_model(self.model, for_concrete_model=False))
Or even PageQuerySet.type
could take a for_concrete_models=False
argument too, which would make it return proxy objects instead of concrete ones. And I wonder if returning proxy objects by default would make sense: I think that's what people would expect but might have some effects on some internal wagtail code (and it's not what django does by default either).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
super().get_queryset()
should return pages with the proxy model class and type(self.model)
should filter them to only include items that are members of that proxy model.
But you're right, I missed for_concrete_models=False
in the .type()
implementation causing that type filter to select pages with the parent type (but still return instances of the proxy model).. Doh!
.type()
just filters the queryset and cannot change the type. So for example, running Page.objects.type(BlogPage)
will return a queryset of Page
objects.
This could be used to simplify the page types rules with the root page. We could create a new from wagtail.wagtailcore.models import Page, RootPage
class HomePage(Page):
# Homepages can only be created at the root level
parent_page_types = [RootPage] |
I like this idea! This fits nicely with the I wonder if we're subverting the purpose of proxy models a bit here - if they're meant to be wrappers that you can freely apply to any instance of the concrete model, rather than an object specifically identifying itself as an instance of the proxy model. Clearly the latter works, though, and it's almost certainly the more useful behaviour for Wagtail to adopt (because allowing page types to appear as multiple types simultaneously is bound to create bigger problems) - so happy to go with this. |
Hi all, any update on if/when this feature might land? |
Any update on this? What kind of help may be needed here? |
I’m playing with a proxy Page model in Wagtail 2.0.
|
If anyone likes to push this further. TODO:
|
I'd be interested in helping to move this forward, it would be so nice to specify different Python behavior for pages without having to create new DB entities... |
Can you tell me where the code can be found? |
Any update? |
Hi all. I just wanted to highlight that using I don't think this is such an issue for Page models, because the Django permission system isn't being used, but this does create a bit of an odd situation, where |
Superseded by #5202 |
This PR includes some tweaks to Wagtail core to allow users to define new page types using proxy models instead of multi-table inheritance. The implementation is currently only for demonstration purposes (not much time).
There's two use-cases I think this would be useful for
Currently (Wagtail 1.1), if you define a proxy page model. Wagtail would add another entry into the "add subpage" view, except it's an exact duplicate of the parent class.
Implementation
To implement this, I've simply gone through
wagtailcore/models.py
and addedfor_concrete_model=False
to each call toget_for_model
. This fixes the issues with "add subpage" and allows pages to be created for these models.By default, proxy models objects attribute returns all instances of their parent class, so I've added a
ProxyPageManager
which filters the pages to only include instances of the proxy model, emulating behaviour of multi-table inheritance. (this manager is currently forced on the proxy model, but I'd like to make this opt-in).Example
Finally, here's the code I created to test this:
Both content types can be created in the admin:
Pages appear to be two distinct types to the user:
And in the shell:
Underneath, there is one database table for both models (they are told apart by the content_type field)