Blog Spass mit Newforms-Admin - Rowlevel-Permissions

Newforms-Admin ist schon eine Weile verfügbar und daher wird es Zeit, sich einmal mit den Features auseinander zu setzen. Dieser Artikel ist der Anfang einer Reihe von Tipps und Tricks zu Newforms-Admin, die nacheinander alle aufeinander aufbauen.

Ein oft gewünschtes Feature im Admin-Interface ist "Lasse den Benutzer nur seine eigenen Einträge bearbeiten", anders ausgedrückt: Rowlevel-Permissions. Eine der einfachsten Aufgaben für das neue Admin-Interface.

Fangen wir wieder einmal mit dem Model an, ein kleines Weblog ist ein gutes Beispiel:

from django.db import models
from django.contrib.auth.models import User

class Entry(models.Model):
    title = models.CharField(max_length=255)
    content = models.TextField()
    author = models.ForeignKey(User)

    def __unicode__(self):
        return self.title

Um das Model mit dem Admin Interface administrieren zu können, ist eine einfache ModelAdmin-Klasse notwendig, bestens aufgehoben in der Datei admin.py (Jahaa):

from django.contrib import admin
from myproject.weblog.models import Entry

class EntryAdmin(admin.ModelAdmin):
    list_display = (
        'title',
        'author',
    )

admin.site.register(Entry, EntryAdmin)

Soweit nichts spektakuläres, mit ein paar Einträgen von verschiedenen Usern sieht die Übersichtsseite so aus:

Nun zur Aufgabe: Um dem Benutzer nur seine Beiträge bearbeiten zu lassen, lässt Newforms-Admin auf einfache Weise zu, das Queryset für die Listenansicht zu bearbeiten. Füge in deine ModelAdmin-Klasse eine Funktion "queryset" hinzu, die die Einträge anhand der User/Autor-Beziehung filtert:

class EntryAdmin(admin.ModelAdmin):
    # ...
    def queryset(self, request):
        return self.model._default_manager.filter(author=request.user)

Das war es auch schon! Jeder Autor sieht ab sofort nur noch seine eigenen Artikel:

Die Sache hat nur einen Haken: Auch Administratoren würden nur ihre eigenen Artikel sehen, irgendwie nicht sehr sinnvoll. Um das Problem zu lösen, schaffen wir uns am einfachsten eine zusätzliche Permission. Erweitere also dein Model wie folgt:

class Entry(models.Model):
    # ...
    class Meta:
        permissions = (
            ('can_view_all', 'Can view all Entries'),
        )

Nach einem "./manage.py syncdb" ist diese neue Permission auch schon verfügbar, die du deinem User zuweisen kannst:

Leider ist nicht genug Voodoo in Django vorhanden, als dass alles automatisch geht. In deiner Queryset-Redefinition musst du noch auf die neue Permission prüfen, etwa so:

def queryset(self, request):
    # ...
    if request.user.has_perm('weblog.can_view_all'):
        return self.model._default_manager.get_query_set()
    return self.model._default_manager.filter(author=request.user)

Und fertig. "Normale" User können nun nur noch ihre eigenen Beiträge bearbeiten während Administratoren oder User mit der Permission "can_view_all" alle Einträge angezeigt bekommen.

Zu guter letzt noch ein Hinweis: Theoretisch könnte man dieses Verhalten auch umdrehen und eine Permission "Can view only his own entries" (*urgs*) schaffen. Das nur fürs Gedächtnis.