Permalink
Browse files

Merge pull request #10 from vdboor/master

Polymorphic admin interface
  • Loading branch information...
2 parents db4cc4d + bba8db1 commit 28b888523683497003a235ff0364ef1e182cdd9b @chrisglass chrisglass committed Aug 6, 2012
View
@@ -12,3 +12,4 @@ Contributors
* Charles Leifer (python 2.4 compatibility)
* Germán M. Bravo
* Martin Brochhaus
+* Diederik van der Boor (polymorphic admin interface)
View
@@ -3,6 +3,12 @@
Changelog
++++++++++
+Juli 5, 2012, Polymorphic admin interface
+=========================================
+
+Added a polymorphic admin interface. The admin interface is able to add polymorphic models,
+and the admin edit screen also displays the custom fields of the polymorphic model.
+
2011-12-20 Renaming, refactoring, new maintainer
================================================
View
@@ -153,6 +153,98 @@ In the examples below, these models are being used::
field3 = models.CharField(max_length=10)
+Using polymorphic models in the admin interface
+-----------------------------------------------
+
+Naturally, it's possible to register individual polymorphic models in the Django admin interface.
+However, to use these models in a single cohesive interface, some extra base classes are available.
+
+The polymorphic admin interface works in a simple way:
+
+* The add screen gains an additional step where the desired child model is selected.
+* The edit screen displays the admin interface of the child model.
+* The list screen still displays all objects of the base class.
+
+The polymorphic admin is implemented via a parent admin that forwards the *edit* and *delete* views
+to the ``ModelAdmin`` of the derived child model. The *list* page is still implemented by the parent model admin.
+
+Both the parent model and child model need to have a ``ModelAdmin`` class.
+Only the ``ModelAdmin`` class of the parent/base model has to be registered in the Django admin site.
+
+The parent model
+~~~~~~~~~~~~~~~~
+
+The parent model needs to inherit ``PolymorphicParentModelAdmin``, and implement the following:
+
+* ``base_model`` should be set
+* ``child_models`` should be set, or:
+
+ * ``get_child_models()`` should return a list with (Model, ModelAdmin) tuple.
+
+The exact implementation can depend on the way your module is structured.
+For simple inheritance situations, ``child_models`` is best suited.
+For large applications, this leaves room for a plugin registration system.
+
+The child models
+~~~~~~~~~~~~~~~~
+
+The admin interface of the derived models should inherit from ``PolymorphicChildModelAdmin``.
+Again, ``base_model`` should be set in this class as well.
+This class implements the following features:
+
+* It corrects the breadcrumbs in the admin pages.
+* It extends the template lookup paths, to look for both the parent model and child model in the ``admin/app/model/change_form.html`` path.
+* It allows to set ``base_form`` so the derived class will automatically include other fields in the form.
+* It allows to set ``base_fieldsets`` so the derived class will automatically display any extra fields.
+
+By adding ``polymorphic`` to the ``INSTALLED_APPS``, the breadcrumbs will be
+fixed as well, to stay the same for all child models.
+
+The standard ``ModelAdmin`` attributes ``form`` and ``fieldsets`` should rather be avoided at the base class,
+because it will hide any additional fields which are defined in the derived model. Instead,
+use the ``base_form`` and ``base_fieldsets`` instead. The ``PolymorphicChildModelAdmin`` will
+automatically detect the additional fields that the child model has, display those in a separate fieldset.
+
+
+Example
+~~~~~~~
+
+::
+
+ from django.contrib import admin
+ from polymorphic.admin import PolymorphicParentModelAdmin, PolymorphicChildModelAdmin
+
+
+ class ModelAChildAdmin(PolymorphicChildModelAdmin):
+ """ Base admin class for all child models """
+ base_model = ModelA
+
+ # By using these `base_...` attributes instead of the regular ModelAdmin `form` and `fieldsets`,
+ # the additional fields of the child models are automatically added to the admin form.
+ base_form = ...
+ base_fieldsets = (
+ ...
+ )
+
+ class ModelBAdmin(ModelAChildAdmin):
+ # define custom features here
+
+ class ModelCAdmin(ModelBAdmin):
+ # define custom features here
+
+
+ class ModelAParentAdmin(PolymorphicParentModelAdmin):
+ """ The parent model admin """
+ base_model = ModelA
+ child_models = (
+ (ModelB, ModelBAdmin),
+ (ModelC, ModelCAdmin),
+ }
+
+ # Only the parent needs to be registered:
+ admin.site.register(ModelA, ModelAParentAdmin)
+
+
Filtering for classes (equivalent to python's isinstance() ):
-------------------------------------------------------------
@@ -504,9 +596,6 @@ Restrictions & Caveats
``extra()`` has one restriction: the resulting objects are required to have
a unique primary key within the result set.
-* Django Admin Integration: There currently is no specific admin integration,
- but it would most likely make sense to have one.
-
* Diamond shaped inheritance: There seems to be a general problem
with diamond shaped multiple model inheritance with Django models
(tested with V1.1 - V1.3).
View
@@ -2,4 +2,4 @@ include README.rst
include LICENSE
include DOCS.rst
include CHANGES.rst
-
+recursive-include polymorphic/templates/ *.html
View
@@ -0,0 +1,63 @@
+from django.contrib import admin
+from polymorphic.admin import PolymorphicParentModelAdmin, PolymorphicChildModelAdmin
+from pexp.models import *
+
+
+class ProjectChildAdmin(PolymorphicChildModelAdmin):
+ base_model = Project
+
+class ProjectAdmin(PolymorphicParentModelAdmin):
+ base_model = Project
+ child_models = (
+ (Project, ProjectChildAdmin),
+ (ArtProject, ProjectChildAdmin),
+ (ResearchProject, ProjectChildAdmin),
+ )
+
+admin.site.register(Project, ProjectAdmin)
+
+
+
+class ModelAChildAdmin(PolymorphicChildModelAdmin):
+ base_model = ModelA
+
+class ModelAAdmin(PolymorphicParentModelAdmin):
+ base_model = ModelA
+ child_models = (
+ (ModelA, ModelAChildAdmin),
+ (ModelB, ModelAChildAdmin),
+ (ModelC, ModelAChildAdmin),
+ )
+
+admin.site.register(ModelA, ModelAAdmin)
+
+
+if 'Model2A' in globals():
+ class Model2AChildAdmin(PolymorphicChildModelAdmin):
+ base_model = Model2A
+
+ class Model2AAdmin(PolymorphicParentModelAdmin):
+ base_model = Model2A
+ child_models = (
+ (Model2A, Model2AChildAdmin),
+ (Model2B, Model2AChildAdmin),
+ (Model2C, Model2AChildAdmin),
+ )
+
+ admin.site.register(Model2A, Model2AAdmin)
+
+
+if 'UUIDModelA' in globals():
+ class UUIDModelAChildAdmin(PolymorphicChildModelAdmin):
+ base_model = UUIDModelA
+
+ class UUIDModelAAdmin(PolymorphicParentModelAdmin):
+ base_model = UUIDModelA
+ child_models = (
+ (UUIDModelA, UUIDModelAChildAdmin),
+ (UUIDModelB, UUIDModelAChildAdmin),
+ (UUIDModelC, UUIDModelAChildAdmin),
+ )
+
+ admin.site.register(UUIDModelA, UUIDModelAAdmin)
+
Oops, something went wrong.

0 comments on commit 28b8885

Please sign in to comment.