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:
#models.py from django.db import models class Section(models.Model) name = models.CharField(max_length=90) slug = models.SlugField(max_length=90) # ... More fields class Article(models.Model): section = models.ForeignKey('Section', null=True, blank=True) # ... more fields class ReviewArticle(Article): class Meta: proxy=True
ReviewArticle is just a Python construct that doesn’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.
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): pass class ReviewArticleAdmin(admin.ModelAdmin): pass def queryset(self, request): return self.model.objects.filter(section__name="reviews") admin.site.register(Article, ArticleAdmin) admin.site.register(ReviewArticle, ReviewArticleAdmin)
Now modify your proxy model so all
ReviewArticle objects are saved in the review section:
class ReviewArticle(Article): class Meta: proxy=True 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
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.