1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
|
Third-party applications support
================================
django-guardian support
-----------------------
.. versionadded:: 1.0.2
You can configure django-guardian_ to use the base model for object level permissions.
Add this option to your settings:
.. code-block:: python
GUARDIAN_GET_CONTENT_TYPE = 'polymorphic.contrib.guardian.get_polymorphic_base_content_type'
This option requires django-guardian_ >= 1.4.6. Details about how this option works are available in the
`django-guardian documentation <https://django-guardian.readthedocs.io/en/latest/configuration.html#guardian-get-content-type>`_.
django-rest-framework support
-----------------------------
The django-rest-polymorphic_ package provides polymorphic serializers that help you integrate your polymorphic models with `django-rest-framework`.
Example
~~~~~~~
Define serializers:
.. code-block:: python
from rest_framework import serializers
from rest_polymorphic.serializers import PolymorphicSerializer
from .models import Project, ArtProject, ResearchProject
class ProjectSerializer(serializers.ModelSerializer):
class Meta:
model = Project
fields = ('topic', )
class ArtProjectSerializer(serializers.ModelSerializer):
class Meta:
model = ArtProject
fields = ('topic', 'artist')
class ResearchProjectSerializer(serializers.ModelSerializer):
class Meta:
model = ResearchProject
fields = ('topic', 'supervisor')
class ProjectPolymorphicSerializer(PolymorphicSerializer):
model_serializer_mapping = {
Project: ProjectSerializer,
ArtProject: ArtProjectSerializer,
ResearchProject: ResearchProjectSerializer
}
Create viewset with serializer_class equals to your polymorphic serializer:
.. code-block:: python
from rest_framework import viewsets
from .models import Project
from .serializers import ProjectPolymorphicSerializer
class ProjectViewSet(viewsets.ModelViewSet):
queryset = Project.objects.all()
serializer_class = ProjectPolymorphicSerializer
django-extra-views
------------------
.. versionadded:: 1.1
The :mod:`polymorphic.contrib.extra_views` package provides classes to display polymorphic formsets
using the classes from django-extra-views_. See the documentation of:
* :class:`~polymorphic.contrib.extra_views.PolymorphicFormSetView`
* :class:`~polymorphic.contrib.extra_views.PolymorphicInlineFormSetView`
* :class:`~polymorphic.contrib.extra_views.PolymorphicInlineFormSet`
django-mptt support
-------------------
Combining polymorphic with django-mptt_ is certainly possible, but not straightforward.
It involves combining both managers, querysets, models, meta-classes and admin classes
using multiple inheritance.
The django-polymorphic-tree_ package provides this out of the box.
django-reversion support
------------------------
Support for django-reversion_ works as expected with polymorphic models.
However, they require more setup than standard models. That's become:
* Manually register the child models with django-reversion_, so their ``follow`` parameter can be set.
* Polymorphic models use `multi-table inheritance <https://docs.djangoproject.com/en/dev/topics/db/models/#multi-table-inheritance>`_.
See the `reversion documentation <https://django-reversion.readthedocs.io/en/latest/api.html#multi-table-inheritance>`_
how to deal with this by adding a ``follow`` field for the primary key.
* Both admin classes redefine ``object_history_template``.
Example
~~~~~~~
The admin :ref:`admin example <admin-example>` becomes:
.. code-block:: python
from django.contrib import admin
from polymorphic.admin import PolymorphicParentModelAdmin, PolymorphicChildModelAdmin
from reversion.admin import VersionAdmin
from reversion import revisions
from .models import ModelA, ModelB, ModelC
class ModelAChildAdmin(PolymorphicChildModelAdmin, VersionAdmin):
base_model = ModelA # optional, explicitly set here.
base_form = ...
base_fieldsets = (
...
)
class ModelBAdmin(ModelAChildAdmin, VersionAdmin):
# define custom features here
class ModelCAdmin(ModelBAdmin):
# define custom features here
class ModelAParentAdmin(VersionAdmin, PolymorphicParentModelAdmin):
base_model = ModelA # optional, explicitly set here.
child_models = (
(ModelB, ModelBAdmin),
(ModelC, ModelCAdmin),
)
revisions.register(ModelB, follow=['modela_ptr'])
revisions.register(ModelC, follow=['modelb_ptr'])
admin.site.register(ModelA, ModelAParentAdmin)
Redefine a :file:`admin/polymorphic/object_history.html` template, so it combines both worlds:
.. code-block:: html+django
{% extends 'reversion/object_history.html' %}
{% load polymorphic_admin_tags %}
{% block breadcrumbs %}
{% breadcrumb_scope base_opts %}{{ block.super }}{% endbreadcrumb_scope %}
{% endblock %}
This makes sure both the reversion template is used, and the breadcrumb is corrected for the polymorphic model.
.. _django-reversion-compare-support:
django-reversion-compare support
--------------------------------
The django-reversion-compare_ views work as expected, the admin requires a little tweak.
In your parent admin, include the following method:
.. code-block:: python
def compare_view(self, request, object_id, extra_context=None):
"""Redirect the reversion-compare view to the child admin."""
real_admin = self._get_real_admin(object_id)
return real_admin.compare_view(request, object_id, extra_context=extra_context)
As the compare view resolves the the parent admin, it uses it's base model to find revisions.
This doesn't work, since it needs to look for revisions of the child model. Using this tweak,
the view of the actual child model is used, similar to the way the regular change and delete views are redirected.
.. _django-extra-views: https://github.com/AndrewIngram/django-extra-views
.. _django-guardian: https://github.com/django-guardian/django-guardian
.. _django-mptt: https://github.com/django-mptt/django-mptt
.. _django-polymorphic-tree: https://github.com/django-polymorphic/django-polymorphic-tree
.. _django-rest-polymorphic: https://github.com/apirobot/django-rest-polymorphic
.. _django-reversion-compare: https://github.com/jedie/django-reversion-compare
.. _django-reversion: https://github.com/etianen/django-reversion
|