PolymorphicView
The crud_views_polymorphic package adds support for django-polymorphic
models. It provides a two-step create flow (select subtype → fill form) and polymorphic-aware
detail, update, and delete views that resolve the correct form based on the actual subtype of
each object.
Installation
Install the polymorphic optional dependency group:
pip install django-crud-views[polymorphic]
Add the required apps to INSTALLED_APPS:
INSTALLED_APPS = [
...
"polymorphic",
"crud_views_polymorphic.apps.CrudViewsPolymorphicConfig",
...
]
Basic Usage
1. Define the model
Inherit from PolymorphicModel for the base class and define concrete subtypes:
from django.db import models
from polymorphic.models import PolymorphicModel
class Vehicle(PolymorphicModel):
name = models.CharField(max_length=128)
class Car(Vehicle):
doors = models.IntegerField()
class Truck(Vehicle):
payload_tons = models.FloatField()
2. Define the ViewSet and views
from django.forms import modelform_factory
from crud_views.lib.viewset import ViewSet
from crud_views.lib.crispy import CrispyModelViewMixin
from crud_views.lib.crispy.form import CrispyDeleteForm
from crud_views_polymorphic.lib import (
PolymorphicCreateViewPermissionRequired,
PolymorphicCreateSelectViewPermissionRequired,
PolymorphicUpdateViewPermissionRequired,
PolymorphicDetailViewPermissionRequired,
)
from crud_views_polymorphic.lib.create_select import PolymorphicContentTypeForm
from crud_views_polymorphic.lib.delete import PolymorphicDeleteViewPermissionRequired
from .models import Vehicle, Car, Truck
cv_vehicle = ViewSet(model=Vehicle, name="vehicle")
CarForm = modelform_factory(Car, fields=["name", "doors"])
TruckForm = modelform_factory(Truck, fields=["name", "payload_tons"])
class VehicleCreateSelectView(CrispyModelViewMixin, PolymorphicCreateSelectViewPermissionRequired):
form_class = PolymorphicContentTypeForm
cv_viewset = cv_vehicle
class VehicleCreateView(CrispyModelViewMixin, PolymorphicCreateViewPermissionRequired):
cv_viewset = cv_vehicle
polymorphic_forms = {
Car: CarForm,
Truck: TruckForm,
}
class VehicleUpdateView(CrispyModelViewMixin, PolymorphicUpdateViewPermissionRequired):
cv_viewset = cv_vehicle
polymorphic_forms = {
Car: CarForm,
Truck: TruckForm,
}
class VehicleDeleteView(CrispyModelViewMixin, PolymorphicDeleteViewPermissionRequired):
form_class = CrispyDeleteForm
cv_viewset = cv_vehicle
class VehicleDetailView(PolymorphicDetailViewPermissionRequired):
cv_viewset = cv_vehicle
cv_property_display = [
{"title": "Attributes", "properties": ["name"]},
]
3. Register URLs
# urls.py
urlpatterns = cv_vehicle.urlpatterns
4. Add the create_select action to the list view
from crud_views.lib.views import ListViewPermissionRequired, ListViewTableMixin
class VehicleListView(ListViewTableMixin, ListViewPermissionRequired):
cv_viewset = cv_vehicle
cv_list_actions = ["detail", "update", "delete"]
cv_context_actions = ["create_select"]
View Classes
| Class | Permission |
|---|---|
PolymorphicCreateSelectView |
— |
PolymorphicCreateSelectViewPermissionRequired |
add |
PolymorphicCreateView |
— |
PolymorphicCreateViewPermissionRequired |
add |
PolymorphicUpdateView |
— |
PolymorphicUpdateViewPermissionRequired |
change |
PolymorphicDeleteView |
— |
PolymorphicDeleteViewPermissionRequired |
delete |
PolymorphicDetailView |
— |
PolymorphicDetailViewPermissionRequired |
view |
Two-step create flow
Creating a polymorphic instance requires two steps:
-
create_select—PolymorphicCreateSelectViewrenders a form with aChoiceFieldof all registered subtypes. On submit it redirects to thecreateURL, passingpolymorphic_ctype_idas a URL parameter. -
create—PolymorphicCreateViewreadspolymorphic_ctype_idfrom the URL, resolves the subtype model via the content-type framework, and renders the matching form frompolymorphic_forms.
Filtering available subtypes
PolymorphicCreateSelectView supports filtering which subtypes appear in the select form:
| Attribute | Type | Description |
|---|---|---|
cv_polymorphic_exclude |
list[type] or None |
Subtypes to hide from the select form |
cv_polymorphic_include |
list[type] or None |
Only these subtypes appear in the select form |
Only one of the two may be set at a time (enforced by system check E220).
polymorphic_forms
Set polymorphic_forms on PolymorphicCreateView and PolymorphicUpdateView to a dict that maps
each subtype model class to its form class:
polymorphic_forms = {
Car: CarForm,
Truck: TruckForm,
}
The correct form is selected at runtime based on the resolved subtype.
System checks
| ID | View | What is checked |
|---|---|---|
E220 |
PolymorphicCreateSelectView |
At most one of cv_polymorphic_exclude / cv_polymorphic_include is set |