- Author:
- bradmontgomery
- Posted:
- June 17, 2009
- Language:
- Python
- Version:
- 1.0
- Score:
- 2 (after 2 ratings)
I'm using Django's FlatPages, but I want to be able to restrict admin access to Users based on a FlatPage url. For example, User John Doe should be able to edit any FlatPage objects whose URL begins with /johndoe/
(such as /johndoe/about/
or /johndoe/projects/whatever/
).
For this to work, John Doe would already need the appropriate admin permissions for FlatPage (such as can_add and can_change).
I have set this up as a separate flatpage_addons app. It consists of the Permission model, which maps a starting URL to one or more django Users. It consists of the minimal necessary admin code so Permissions can be created using the admin.
The bulk of this code consists of the ifhasflatpagepermission template tag as well as the flatpage_result_list inclusion tag. The former works much like django's existing if, else, endif tags while the latter is modified from the django admin's result_list inclusion tag.
This may not be the most elegant solution to my problem, but so far it works for me. Any comments or suggestions are welcome!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | #########################
# models.py
#########################
from django.db import models
from django.contrib.flatpages.models import FlatPage
from django.contrib.auth.models import User
class Permission(models.Model):
'''
A mapping of Flatpage URLs to Users.
NOTE: for this to work, the user must already have
permissions to edit FlatPages.
'''
url = models.CharField(max_length=255, \
help_text='The selected Users will be able to edit all FlatPages \
that begin with this URL. For example: "/johndoe/"')
users = models.ManyToManyField(User, related_name="flatpagepermission")
def __unicode__(self):
return self.url
class Meta:
ordering = ['url', ]
def user_has_flatpage_permission(user, url):
'''
A helper function to check to see if the given user has
permission to edit the flatpage associated with the given URL.
user = a django.contrib.auth.models.User object
url = a URL fragment for a FlatPage. E.g. /about/something/else
'''
if user.is_superuser:
return True
perms = Permission.objects.filter(users=user)
for p in perms:
if url.startswith(p.url):
return True
return False
#########################
# admin.py
#########################
from flatpage_addons.models import Permission
from django.contrib import admin
class PermissionAdmin(admin.ModelAdmin):
list_display = ('url', )
admin.site.register(Permission, PermissionAdmin)
##################################
# templatetags/flatpage_addons_extras.py
##################################
from django import template
from django.template import Variable, VariableDoesNotExist
from django.contrib.auth.models import User
from de_concierge.flatpage_addons.models import user_has_flatpage_permission
from django.contrib.admin.templatetags import admin_list
register = template.Library()
def results(user, cl):
'''
Modified from django.contrib.admin.templatetags.admin_list
Generates a list of items for the Admin's change_list page.
This function filters out those FlatPage objects that do
for which the current user does not have Permission.
'''
for res in cl.result_list:
if user_has_flatpage_permission(user, res.url):
yield list(admin_list.items_for_result(cl,res))
@register.inclusion_tag('admin/change_list_results.html')
def flatpage_result_list(user, cl):
'''
Based on django.contrib.admin.templatetag.admin_list.result_list;
An inclusion tag that omits flatpages that the user
does not have permission to edit.
'''
return {'cl':cl,
'result_headers':list(admin_list.result_headers(cl)),
'results': list(results(user, cl))}
class IfHasFlatPagePermissionNode(template.Node):
'''
Execute code in this block if the given User has permission to
the given FlatPage URL.
'''
def __init__(self, user, url, nodelist_true, nodelist_false):
self.user = Variable(user)
self.url = Variable(url)
self.nodelist_true = nodelist_true
self.nodelist_false = nodelist_false
def __repr__(self):
return "<IfHasFlatPagePermissionNode>"
def render(self, context):
try:
user_obj = self.user.resolve(context)
flatpage_url = self.url.resolve(context)
if user_has_flatpage_permission(user_obj, flatpage_url):
return self.nodelist_true.render(context)
except VariableDoesNotExist:
pass
return self.nodelist_false.render(context)
def do_ifhasflatpagepermission(parser, token):
'''
Parser for Template:
{% ifhasflatpagepermission <user> <url> %}
{# execute contents #}
{% endifhasflatpagepermission %}
'''
bits = list(token.split_contents())
if len(bits) != 3:
raise template.TemplateSyntaxError, "%r takes 2 arguments: a User object and a URL."%bits[0]
end_tag = 'end' + bits[0]
nodelist_true = parser.parse(('else', end_tag))
token = parser.next_token()
if token.contents == 'else':
nodelist_false = parser.parse((end_tag, ))
parser.delete_first_token()
else:
nodelist_false = template.NodeList()
return IfHasFlatPagePermissionNode(bits[1], bits[2], nodelist_true, nodelist_false)
# Register the new tag
register.tag('ifhasflatpagepermission', do_ifhasflatpagepermission)
##########################################
# Lastly, we override the change_form.html and the
# change_list.html admin templates for the flatpage app:
# /my_project/templates/admin/flatpages/flatpage/
##########################################
##########################################
# change_form.html
##########################################
{% extends "admin/change_form.html" %}
{% load flatpage_addons_extras %}
{% block content %}
{% ifhasflatpagepermission user original.url %}
{{ block.super }}
{% else %}
<h1> You do not have permission to Edit this page </h1>
{% endifhasflatpagepermission %}
{% endblock %}
##########################################
# change_list.html
##########################################
{% extends "admin/change_list.html" %}
{% load adminmedia admin_list i18n %}
{% load flatpage_addons_extras %}
{% block result_list %}
{# {% result_list cl %} #}
{% flatpage_result_list user cl %}
{% endblock %}
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 6 months ago
Comments
The admin part looks complicated to me. I guess it's enough to just overwrite the ModelAdmin.queryset method to filter the rows that the user has permission to.
#
bartTC, I'm assuming you meant the admin template part? I really didn't want to touch the flatpage code, so that's why I just override the template (which I'm doing for flatpages anyway). I'm sure this is not the best solution, but it solves my problems :)
#
Please login first before commenting.