a blog about programming, photography and electronics.

Adding additional views to django admin

Posted: May 17th, 2010 | Author: | Filed under: django | Tags: , | 2 Comments »

Today I wanna show you a simple way to add an additional view to the admin site.
Imagine that you want to create a view to review a model, something like send an email to the site owner with your thoughs (or your changes) about an entry.

First we need to define a simple model (of course you can use your existing model):

from django.db import models
 
class MyEntry(models.Model):
    title = models.CharField(max_length=100)
    body = models.TextField()
 
    def __unicode__(self):
        return self.title
 
    class Meta(object):
        verbose_name = 'My Entry'
        verbose_name_plural = 'My Entries'

Once you have defined the model you need to register it to the admin site.

from django.contrib import admin
 
from my_test.models import *
 
admin.site.register(MyEntry)

Now you can see your model under the django admin site:

Ok it works, let’s add a simple entry like this:


Just to test if it works.

Now it’s time to create the view and map it to the admin, simply subclassing the default ModelAdmin class:

from django.contrib import admin
from django.template import RequestContext
from django.conf.urls.defaults import patterns
from django.shortcuts import render_to_response
 
from my_test.models import *
 
class MyEntryAdmin(admin.ModelAdmin):
    review_template = 'admin/my_test/myentry/review.html'
 
    def get_urls(self):
        urls = super(MyEntryAdmin, self).get_urls()
        my_urls = patterns('',
            (r'\d+/review/$', self.admin_site.admin_view(self.review)),
        )
        return my_urls + urls
 
    def review(self, request, id):
        entry = MyEntry.objects.get(pk=id)
 
        return render_to_response(self.review_template, {
            'title': 'Review entry: %s' % entry.title,
            'entry': entry,
            'opts': self.model._meta,
            'root_path': self.admin_site.root_path,
        }, context_instance=RequestContext(request))
 
admin.site.register(MyEntry, MyEntryAdmin)

In this example I have added a view ovverriding the get_urls method. Notice that we need to wrap our view with self.admin_site.admin_view in order to check permission.

One of the last thing to do is create the template for the view. Let’s do it extending the admin base site template:

{% extends "admin/base_site.html" %}
{% load i18n admin_modify adminmedia %}
{% block extrahead %}{{ block.super }}
{% url admin:jsi18n as jsi18nurl %}
<script src="{{ jsi18nurl|default:" type="text/javascript"><!--mce:0--></script>
{% endblock %}
{% block extrastyle %}{{ block.super }}
{% endblock %}
{% block bodyclass %}{{ opts.app_label }}-{{ opts.object_name.lower }} change-form{% endblock %}
{% block breadcrumbs %}{% if not is_popup %}
<div class="breadcrumbs">
     <a href="../../../../">{% trans "Home" %}</a><a href="../../../">{{ opts.app_label|capfirst|escape }}</a><a href="../../">{{ opts.verbose_name_plural|capfirst }}</a><a href="../">{{ opts.verbose_name|capfirst }} #{{ entry.pk }}</a> ›
     {% trans 'Review Entry' %}</div>
{% endif %}{% endblock %}
{% block content %}
<form action="." method="post">
<fieldset class="module aligned">
<div class="form-row">
      <label>Entry</label>
      <textarea style="height: 136px; width: 161px; margin: 2px;" rows="10">{{ entry.body }}</textarea></div></fieldset>
<div class="submit-row">
<input class="default" type="submit" value="{% trans 'Review' %}" /></div>
</form>
 
{% endblock %}

Let’s go to the url of the view, in my case http://localhost:8000/admin/my_test/myentry/1/review/. We should see something like this:


Ok, we got the view working, nice! But we don’t want to manually insert the url every time. So let’s add the url to the change model view, in order to get this:

We need to ovveride the default change model template creating a template under template_dir/admin/my_app/my_model/change_form.html (change this based on your configuration)

with this markup:

{% extends "admin/change_form.html" %}
{% load i18n %}
{% block object-tools %}
{% if change %}{% if not is_popup %}
<ul class="object-tools">
	<li><a class="historylink" href="history/">{% trans "History" %}</a></li>
	<li><a class="historylink" href="review/">{% trans "Review" %}</a></li>
{% if has_absolute_url %}
	<li><a class="viewsitelink" href="../../../r/{{ content_type_id }}/{{ object_id }}/">{% trans "View on site" %}</a></li>
{% endif%}</ul>
{% endif %}{% endif %}
{% endblock %}

That’s all! If you have some problem with this code, add a comment or contact me.


2 Comments on “Adding additional views to django admin”

  1. 1 goblin89 said at 5:09 am on October 25th, 2010:

    Thanks, that’s useful.

    There seems to be a typo in url pattern, though. Should look like ‘(?P\d+)/review/$’ or ‘(\d+)/review/$’, but not ‘(?P\d+)/review/$’: you may get an ‘unknown specifier’ error by re module because of missing group name after ‘?P’.

  2. 2 admin said at 5:41 am on October 25th, 2010:

    you’re right! thanks ;)


Leave a Reply