File: third-party.rst

package info (click to toggle)
django-polymorphic 4.1.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 892 kB
  • sloc: python: 6,784; javascript: 263; makefile: 137
file content (192 lines) | stat: -rw-r--r-- 6,590 bytes parent folder | download | duplicates (5)
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