[Django]-Add django class based view to admin site

2👍

as_view() method of class-based view returns regular view so you can call it from ModelAdmin like this:

def review(self, request, id):
    return MyReviewView.as_view()(request, id)

8👍

Let say you have the following class based view:

# File: views.py
class MyAwesomeBookView(TemplateView):
    pass

To use this view, you have to make it callable

# File: views.py
awesome_book_view = MyAwesomeBookView.as_view()

Once your view is callable, you can pretty much treat it like how you treat a function-based view.

To link it to the admin urls, you could do something like this:

# File: admin.py
@admin.register(Book)
class BookModelAdmin(admin.ModelAdmin):

    def get_urls(self):
        urls = super().get_urls()
        my_urls = [
            url(r'^awesome-books/$', 
                self.admin_site.admin_view(awesome_book_view)),
        ]
        return my_urls + urls
👤Yeo

5👍

For a full integration with Django admin templates, you can pass the model admin as an extra argument to the class based view, then use it to add some sugar to the context:

file admin.py:

from django.contrib import admin
from .models import MyModel
from .views import ProcessObjectView

@admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):

    def get_urls(self):
        info = self.model._meta.app_label, self.model._meta.model_name
        urls = super().get_urls()
        my_urls = patterns('',
            url(r'^(?P<object_id>.*)/process/$',
                self.admin_site.admin_view(ProcessObjectView.as_view()),
                {'model_admin': self, },
                name="%s_%s_process" % info),
        )
        return my_urls + urls

file views.py

from django.contrib.auth import get_permission_codename

class ProcessObjectView(UpdateView):

    model = MyModel
    pk_url_kwarg = "object_id"
    fields = [... ]
    template_name = 'admin/backend/mymodel/process_object.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        # see http://www.slideshare.net/lincolnloop/customizing-the-django-admin
        model_admin = self.kwargs['model_admin']
        opts = model_admin.model._meta
        admin_site = model_admin.admin_site
        has_perm = self.request.user.has_perm(opts.app_label + '.' + get_permission_codename('change', opts))
        context.update({
            'admin_site': admin_site.name,
            'title': 'Process: ' + str(self.get_object()),
            'opts': opts,
            'app_label': opts.app_label,
            'has_chage_permission': has_perm,
        })

        return context

file process_object.html:

{% extends "admin/change_form.html" %}
{% load i18n utils_tags %}

{% block content %}
...

2👍

You can pass the class based view’s as_view directly, without need of having a variable like awesome_book_view as suggested by another answer:

Example:

in admin.py I have:

class EmailAdmin(admin.ModelAdmin):

    def get_urls(self):
        urls = super(EmailAdmin, self).get_urls()
        my_urls = [
            url(r'^send_email/$',
                self.admin_site.admin_view(SendEmailAdminView.as_view())),
        ]
        return my_urls + urls

admin.site.register(Email, EmailAdmin)

in views.py I have:

class SendEmailAdminView(View):

    def get(self, request):
        pass

    def post(self, request):
        pass

I have removed most of the code for brevity and have kept only relevant part. You can see the full code here.

👤avi

Leave a comment