Skip to content
Back to top
View this page
Edit this page

# Integrations

When integrating polymorphic models into third party apps you have three primary options:

0. Hope it just works (it might!).

1. Ensure the querysets the third party apps see are `not polymorphic`.

2. Override or extend relevant third party app code to work with polymorphic querysets.

If it does not just work, option 1 is usually the easiest. We provide some integrations in `polymorphic.contrib` for popular third party apps and provide guidance for others below.

This page does not exhaustively cover all integrations. If you feel your integration need is very common you may consider opening a PR to either provide support in code or documentation here.

This page covers supported and tested integration advice. For all other integration advice please refer to our integrations discussion page.

For the integration examples on this page, we use the following polymorphic model hierarchy:

     1from django.db import models
     2from polymorphic.models import PolymorphicModel
     3
     4
     5class Article(PolymorphicModel):
     6    title = models.CharField(max_length=100)
     7    content = models.TextField()
     8    created = models.DateTimeField(auto_now_add=True)
     9
    10    def __str__(self):
    11        return self.title
    12
    13
    14class BlogPost(Article):
    15    author = models.CharField(max_length=100)
    16
    17
    18class NewsArticle(Article):
    19    source = models.CharField(max_length=100)

## django-guardian

Added in version 1.0.2.

No special modifications are required to integrate with django-guardian. However, if you would like all object level permissions to be managed at the base model level, rather than have unique permissions for each polymorphic subclass, then you can use the helper function `polymorphic.contrib.guardian.get_polymorphic_base_content_type()` to unify the permissions for your entire polymorphic model tree into a single namespace a the base level:

    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.

## django-extra-views

Added in version 1.1.

The `polymorphic.contrib.extra_views` package provides classes to display polymorphic formsets using the classes from django-extra-views. See the documentation of:

- `PolymorphicFormSetView`

- `PolymorphicInlineFormSetView`

- `PolymorphicInlineFormSet`

Tip

The complete working code for this example can be found in the extra_views integration test.

### Example View

Here’s how to create a view using `PolymorphicFormSetView` to handle polymorphic formsets:

     1from polymorphic.contrib.extra_views import PolymorphicFormSetView
     2from polymorphic.formsets import PolymorphicFormSetChild
     3from django.urls import reverse_lazy
     4from ..models import Article, BlogPost, NewsArticle
     5
     6
     7class ArticleFormSetView(PolymorphicFormSetView):
     8    model = Article
     9    template_name = "extra_views/article_formset.html"
    10    success_url = reverse_lazy("extra_views:articles")
    11    fields = "__all__"
    12
    13    # extra will add two empty forms for models in the order of their appearance
    14    # in formset_children
    15    factory_kwargs = {"extra": 2, "can_delete": True}
    16
    17    formset_children = [
    18        PolymorphicFormSetChild(BlogPost, fields="__all__"),
    19        PolymorphicFormSetChild(NewsArticle, fields="__all__"),
    20    ]

### URL Configuration

Configure the URL patterns to route to your formset view:

    1from django.urls import path
    2from .views import ArticleFormSetView
    3
    4app_name = "extra_views"
    5
    6urlpatterns = [
    7    path("articles/", ArticleFormSetView.as_view(), name="articles"),
    8]

### Template

The template for rendering the formset:

    {% load extra_views_tags %}
    <!DOCTYPE html>
    <html>
    <head>
        <title>Article Formset</title>
    </head>
    <body>
        <h1>Article Formset</h1>
        <form method="post">
            {% csrf_token %}
            {{ formset.management_form }}
            {% for form in formset %}
                <div class="formset-form">
                    <h3>{{ form.instance|model_name }}</h3>
                    {{ form.as_p }}
                </div>
            {% endfor %}
            <button type="submit">Save</button>
        </form>
    </body>
    </html>

`model_name` is a template tag implemented like so:

    @register.filter
    def model_name(instance):
        """Get the model class name of an instance."""
        return instance._meta.verbose_name.title()

## django-reversion

Support for django-reversion works as expected with polymorphic models. We just need to do two things:

1. Inherit our admin classes from both `PolymorphicParentModelAdmin` / `PolymorphicChildModelAdmin` and VersionAdmin.

2. Override the `admin/polymorphic/object_history.html` template.

Tip

The complete working code for this example can be found in the reversion integration test.

### Admin Configuration

The admin configuration combines `PolymorphicParentModelAdmin` and `PolymorphicChildModelAdmin` with VersionAdmin:

     1from django.contrib import admin
     2from polymorphic.admin import PolymorphicParentModelAdmin, PolymorphicChildModelAdmin
     3from reversion.admin import VersionAdmin
     4from ..models import Article, BlogPost, NewsArticle
     5
     6
     7class ArticleChildAdmin(PolymorphicChildModelAdmin, VersionAdmin):
     8    base_model = Article
     9
    10
    11@admin.register(BlogPost)
    12class BlogPostAdmin(ArticleChildAdmin):
    13    pass
    14
    15
    16@admin.register(NewsArticle)
    17class NewsArticleAdmin(ArticleChildAdmin):
    18    pass
    19
    20
    21class ArticleParentAdmin(VersionAdmin, PolymorphicParentModelAdmin):
    22    """
    23    Parent admin for Article model with reversion support.
    24
    25    Note: VersionAdmin must come before PolymorphicParentModelAdmin
    26    in the inheritance order.
    27    """
    28
    29    base_model = Article
    30    child_models = (BlogPost, NewsArticle)
    31    list_display = ("title", "created")
    32
    33
    34admin.site.register(Article, ArticleParentAdmin)

### Custom Template

Since both `PolymorphicParentModelAdmin` and VersionAdmin. define `object_history.html` template, you need to create a custom template that combines both:

    {% 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 using the `breadcrumb_scope` tag.

- djangorestframework
  - Usage
  - Customize resource type