Primary image for Using Proxy Models to Customize the Django Admin

Using Proxy Models to Customize the Django Admin

Fellow Lincoln Looper, Martin Mahner, posted an excellent write up on how to use proxy models to separate staff and user accounts in Django’s admin. We frequently have a need for this in client projects, but people don’t often consider proxy models for this functionality. Here’s another scenario we came across recently where they came in useful.


Proxy Models were introduced in Django 1.1. The official documentation describes their usage, comparing and contrasting them with Model inheritance. One fact the official documentation does not explicitely state is that django won’t let you register multiple ModelAdmins to the same Model. This is where proxy models can come to the rescue.


Consider a newsroom application with articles that must be categorized into sections:
from django.db import models

<span class="k">class</span> <span class="nc">Section</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">)</span>
    <span class="n">name</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">90</span><span class="p">)</span>
    <span class="n">slug</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">SlugField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">90</span><span class="p">)</span>
    <span class="c1"># &#8230; More fields</span>

<span class="k">class</span> <span class="nc">Article</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
    <span class="n">section</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ForeignKey</span><span class="p">(</span><span class="s1">&#39;Section&#39;</span><span class="p">,</span> <span class="n">null</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">blank</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
    <span class="c1"># &#8230; more fields</span>

<span class="k">class</span> <span class="nc">ReviewArticle</span><span class="p">(</span><span class="n">Article</span><span class="p">):</span>
    <span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
        <span class="n">proxy</span><span class="o">=</span><span class="kc">True</span>

Here, ReviewArticle is just a Python construct that doesn&#8217;t change the underlying database structure. It simply provides a way to logically segregate objects within the same model/table.


Benefits of Proxy Models

A typical usecase for proxy models is to overwrite the Python behavior of a model, by changing its default manager or class methods. As noted by Martin, proxy models are great for “faking” content separation in the admin. In addition, a new set of permissions is automatically setup for your proxy model: can add, can change, can delete.

This lets us present a different user experience for objects that are really in the same database table. In our example above, we can give admins a place to edit review articles that is customized specifically for the needs of review articles, even though under the hood, they are the same data model.

ModelAdmin Example

Here’s a simple example of using a proxy model in the Django admin

from django.contrib import admin
from myapp.models import Article, ReviewArticle

class ArticleAdmin(admin.ModelAdmin):
class ReviewArticleAdmin(admin.ModelAdmin):
    def queryset(self, request):
        return self.model.objects.filter(section__name="reviews"), ArticleAdmin), ReviewArticleAdmin)
Now modify your proxy model so all ReviewArticle objects are saved in the review section:
class ReviewArticle(Article):
    class Meta:
    def save(self, *args, **kwargs):
        self.section = Section.objects.get(name='reviews')
        super(ReviewArticle, self).save(*args, **kwargs)
This is a trivial example, but with the customization options available in the Django admin, you can present a very different interface to your users. There are lots of options you can tweak in the ModelAdmin, including:
  • list_filter
  • list_display
  • search_fields
  • inlines


This simple solution can lead to a drastic improvements to the user experience. It is easily maintainable and doesn’t require having to dive into customizing the admin HTML/CSS.

Yann Malet

About the author

Yann Malet

Yann builds and architects performant digital platforms for publishers. In 2015, Yann co-authored High-Performance Django with Peter Baumgartner. Prior to his involvement with Lincoln Loop, Yann focused on Product Lifecycle Management systems (PLM) for several large …