Customize django admin page from the scratch

In my last project with django, I had to modify and extend django admin page massively, there were cases when I had to wipe out curren admin page and create on my own. Usually people don’t go through this kind of trouble I guess, they just write their own model and view rather than admin page. That could possibly be a work around. But I decided not to do that because django admin provides a lot more thing and actually it felt to be the right way to do that. There were no straight forward tutorial that covers all that so here I go, I can guide you a little bit on your way.


Usually when we don’t define our own admin page, but instead we use admin of django.contrib.


from django.contrib import admin

Now for our own admin page we will extend AdminSite.

class MySiteAdminSite(admin.AdminSite):
    site_header = 'This is my Custom Admin Site'

It will not come into action unless we add this to

import admin

urlpatterns = patterns('',

    # (r'^admin/', include(,
     url(r'^admin/', include(admin.my_admin_site.urls)),

)+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)


Our admin page is working but there is no model registered to our admin page, so there is nothing to show.

class ArticleAdmin(admin.ModelAdmin):

    fields =('author','title' ,'slug','body', 'categories','cover')
    def change_view(self, request,object_id, form_url='', extra_context=None):
        extra_context = extra_context or {}
        extra_context["show_save_as_draft"] = True

        return super(ArticleAdmin, self).change_view(request,object_id, form_url, extra_context)

    prepopulated_fields = {'slug': ('title',) }

    def save_model(self, request, obj, *kwwargs):
        if not
            obj.slug = slugify(obj.title)
        if request.user.is_superuser or
            super(ArticleAdmin,self).save_model(request, obj, *kwwargs)
            super(ArticleAdmin,self).save_model(request, obj, *kwwargs)

    def queryset(self, request):
        qs = super(ArticleAdmin, self).queryset(request)

        if request.user.is_superuser:
            return qs
            return qs.filter(author=request.user)

my_admin_site.register(Article, ArticleAdmin)

I actually wrote quite a lot code at my ArticleAdmin, I am going to explain it now. Basically we override  change_view, save_model and queryset method of modelAdmin class. change_view is responsible for embeding edit or create new form. This is what change_form.html look like:

You can pass your variable via extra_context, for my case I passed show_save_as_draft. and I edited change_form.html and put my edited version of it at template/admin/app/change_form.html

At save model, I actually checked some permission and slugify the link. pretty straight forward.

Now queryset is pretty interesting, it usually shows all the articles, does not it? what if we want that when a certain user logs in you want him to show only his articles? This is exactly what I did with filter.


Now we have a working custom admin that shows stuff at its dashboard, we are yet to modify our admin page.

class StripeAdminSite(admin.AdminSite):

    def index(self, request, extra_context=None):
        extra_context = extra_context or {}
        extra_context["site_visited_by"] = 10000

        return super(StripeAdminSite, self).index(request,extra_context)

    def censor_article(self,request,id):
            if request.user.is_superuser or
        except Article.DoesNotExist:

        from django.http import HttpResponseRedirect
        return HttpResponseRedirect(request.META.get('HTTP_REFERER'))

    def get_urls(self):
        urls = super(MyAdminSite, self).get_urls()
        from django.conf.urls import url
        my_urls = [
            url(r'^article/censor/(?P<id>w+)/$', self.censor_article),

        return my_urls + urls


Here, index is what is being displayed when you hit /admin.  Your current index looks like this:

You can override it by putting your own index.html at /template/admin/index.html you can pass variables via extra_context parameter of index function.

I wrote a view fuction censor_article at admin class and added corresponding url at get_urls function. Thats basically it.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s