Skip to content

Instantly share code, notes, and snippets.

@glarrain
Created July 11, 2013 22:08
Show Gist options
  • Save glarrain/5979690 to your computer and use it in GitHub Desktop.
Save glarrain/5979690 to your computer and use it in GitHub Desktop.
Django custom admin site. App name `custom_admin`
{% load admin_static %}{% load url from future %}<!DOCTYPE html>
<html lang="{{ LANGUAGE_CODE|default:"en-us" }}" {% if LANGUAGE_BIDI %}dir="rtl"{% endif %}>
{% comment %}
This template is almost a copy (with indentation corrections and modifications listed below) of
'django/contrib/admin/templates/admin/base.html' and overrides it by living in directory
'/templates/admin/', as instructed in documentation:
"For those templates that cannot be overridden in this way, you may still override them for
your entire project. Just place the new version in your templates/admin directory."
https://docs.djangoproject.com/en/1.4/ref/contrib/admin/#overriding-admin-templates
Modifications:
* removed ` and user.is_staff` from "if" around div "user-tools"
* added `{% if show_user_links %}` around block "userlinks"
* moved the logout link out and below that block
{% endcomment %}
<head>
<title>{% block title %}{% endblock %}</title>
<link rel="stylesheet" type="text/css" href="{% block stylesheet %}{% static "admin/css/base.css" %}{% endblock %}" />
{% block extrastyle %}{% endblock %}
<!--[if lte IE 7]><link rel="stylesheet" type="text/css" href="{% block stylesheet_ie %}{% static "admin/css/ie.css" %}{% endblock %}" /><![endif]-->
{% if LANGUAGE_BIDI %}<link rel="stylesheet" type="text/css" href="{% block stylesheet_rtl %}{% static "admin/css/rtl.css" %}{% endblock %}" />{% endif %}
<script type="text/javascript">window.__admin_media_prefix__ = "{% filter escapejs %}{% static "admin/" %}{% endfilter %}";</script>
{% block extrahead %}{% endblock %}
{% block blockbots %}<meta name="robots" content="NONE,NOARCHIVE" />{% endblock %}
</head>
{% load i18n %}
<body class="{% if is_popup %}popup {% endif %}{% block bodyclass %}{% endblock %}">
<!-- Container -->
<div id="container">
{% if not is_popup %}
<!-- Header -->
<div id="header">
<div id="branding">
{% block branding %}
<h1 id="site-name">
<img src="{% static 'images/lookup-index-logo-small.png' %}"
alt="LookUP" width="200" height="82">
</h1>
{% endblock %}
</div>
{% if user.is_active %}
<div id="user-tools">
{% if show_user_tools %}
{% trans 'Welcome,' %}
<strong>{% filter force_escape %}{% firstof user.first_name user.username %}{% endfilter %}</strong>.
{% block userlinks %}
{% url 'django-admindocs-docroot' as docsroot %}
{% if docsroot %}
<a href="{{ docsroot }}">{% trans 'Documentation' %}</a> /
{% endif %}
<a href="{% url 'admin:password_change' %}">{% trans 'Change password' %}</a> /
{% endblock %}
{% endif %}
<a href="{% url 'admin:logout' %}">{% trans 'Log out' %}</a>
</div>
{% endif %}
{% block nav-global %}{% endblock %}
</div>
<!-- END Header -->
{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
{% if title %} &rsaquo; {{ title }}{% endif %}
</div>
{% endblock %}
{% endif %}
{% block messages %}
{% if messages %}
<ul class="messagelist">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endblock messages %}
<!-- Content -->
<div id="content" class="{% block coltype %}colM{% endblock %}">
{% block pretitle %}{% endblock %}
{% block content_title %}
{% if title %}<h1>{{ title }}</h1>{% endif %}
{% endblock %}
{% block content %}
{% block object-tools %}{% endblock %}
{{ content }}
{% endblock %}
{% block sidebar %}{% endblock %}
<br class="clear" />
</div>
<!-- END Content -->
{% block footer %}<div id="footer"></div>{% endblock %}
</div>
<!-- END Container -->
</body>
</html>
{% extends "admin/base.html" %}
{% load i18n %}
{% comment %}
This template is based on 'django/contrib/admin/templates/admin/base.html' and overrides it by
living in directory '/templates/admin/', as instructed in documentation:
"For those templates that cannot be overridden in this way, you may still override them for
your entire project. Just place the new version in your templates/admin directory."
https://docs.djangoproject.com/en/1.4/ref/contrib/admin/#overriding-admin-templates
{% endcomment %}
{% block title %}
{{ title }} | {% if site %}{{ site.name }}{% else %}{% trans 'Django site admin' %}{% endif %}
{% endblock %}
{% block branding %}
{{ block.super }}
{% endblock %}
{% block nav-global %}{% endblock %}
import django.contrib.admin.forms
import django.contrib.auth.forms
class AdminCustomAuthForm(django.contrib.admin.forms.AdminAuthenticationForm):
"""Custom admin.forms.AdminAuthenticationForm that "replaces"
:meth:`clean` with the one from its superclass
auth.forms.AuthenticationForm.
The purpose is to remove references to ``user.is_staff``.
"""
def clean(self):
return django.contrib.auth.forms.AuthenticationForm.clean(self)
"""Module equivalent to :mod:`django.contrib.admin.options`, where
:class:`ModelAdmin` lives.
"""
import django.contrib.admin.options
class CustomModelAdmin(django.contrib.admin.options.ModelAdmin):
"""Custom ModelAdmin that overrides :meth:`get_actions`."""
def get_actions(self, request):
"""Remove action "delete" if :meth:`has_delete_permission` is False
for ``obj=None``.
``obj=None`` means *any* object of the given model. Thus, if the
user can't delete any of the objects, remove the delete action.
"""
# the hardcoded string is from AdminSite's constructor
delete_action_key = 'delete_selected'
actions = super(CustomModelAdmin, self).get_actions(request)
if not self.has_delete_permission(request, obj=None):
actions.pop(delete_action_key, None) # "safe" pop
return actions
import django.contrib.admin
from . import forms
class CustomAdminSite(django.contrib.admin.AdminSite):
"""Custom AdminSite that:
* optionally removes the check for user attribute ``is_staff``
* checks for a given set of permissions
* overrides ``index_template``, ``login_template``
* adds :attr:`title`
* overrides :meth:`index` to use :attr:`title` and :attr:`show_user_tools`
Partly inspired in
* http://www.tryolabs.com/Blog/2012/06/18/django-administration-interface-non-staff-users/
* https://docs.djangoproject.com/en/1.4/ref/contrib/admin/
* http://stackoverflow.com/a/11225984/556413
"""
login_form = forms.AdminCustomAuthForm
def __init__(self, name='admin', app_name='admin',
title=None, check_user_is_staff=False,
required_permissions=None, show_user_tools=True, **kwargs):
"""Constructor
:param title: of the admin site
:param check_user_is_staff: whether to verify that
``user.is_staff`` is True
:param required_permissions: user permissions to require for viewing
pages in this site
:type required_permissions: iterable of strings,
**not** permission objects e.g. ``('app.permission_name', )``
:param show_user_tools: whether to display links for user e.g.
change password, close session
"""
super(CustomAdminSite, self).__init__(name, app_name, **kwargs)
self.title = title
self.check_user_is_staff = check_user_is_staff
self.required_permissions = required_permissions
self.show_user_tools = show_user_tools
def has_permission(self, request):
"""Return whether ``request`` is allowed to view pages in this site.
True if user:
* is active, and
* is staff (if :attr:`check_user_is_staff` is True), and
* has all the permissions in :attr:`required_permissions`
Based in :meth:`AdminSite.has_permission`, optionally removes the check
of ``request.user``'s attribute ``is_staff``.
"""
if self.check_user_is_staff:
if not request.user.is_staff:
return False
if self.required_permissions:
if not request.user.has_perms(self.required_permissions):
return False
return request.user.is_active
def index(self, request, extra_context=None, **kwargs):
"""Override to set ``title`` in ``extra_context``."""
# TODO: should we add the decorator "never_cache" here too?
if self.title:
ctx = {'title': self.title, 'show_user_tools': self.show_user_tools}
if extra_context is None:
extra_context = ctx
else:
extra_context.update(ctx)
return super(CustomAdminSite, self).index(request, extra_context,
**kwargs)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment