[Django] Dinge limitieren anhand User-Typ oder User-Gruppe

Django, Flask, Bottle, WSGI, CGI…
Antworten
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Sicherlich habt ihr schon mal das selbe Problem gehabt:

Man möchte z.B. die sichtbarkeit eines Eintrags (z.B.: Blog-Eintrag, oder eine Seite) limitieren. Und das wahlweise anhand von User-Typ (Anonymous, staff- oder super-user) oder anhand einer existierenden User-Gruppe...

Entweder macht man es sich einfach, lässt die User-Typen weg und macht nur einen models.ForeignKey zu auth.models.Group

Wenn man allerdings die User-Typen drin haben will, hat man ein Problem. Zusätzliche models.BooleanField() jeweils für Anonymous, staff- und super-user ist doch recht unpraktisch.

Ich hab nun was gebastelt, damit man mit nur einem Feld zwischen User-Typ und User-Gruppe gleichzeitig wählen kann:
https://github.com/jedie/django-tools/b ... rgroups.py

Im Grunde ist es ein models.IntegerField() welches "choices" Benutzt, welches dann ungefähr so aussieht:

Code: Alles auswählen

CHOICES = [
        (0, _("anonymous users")),
        (-1, _("staff users")),
        (-2, _("superusers")),
        (1, _("Erste auth.models.Group")),
        (2, _("Zweite auth.models.Group")),
        ...
    ]
Dazu gibt es ein paar Hilfsfunktionen, damit man schneller auswerten kann, ob der User nun zugriff hat, oder nicht.

Ein Model kann Beispielsweise so aussehen:

Code: Alles auswählen

from django_tools import limit_to_usergroups

class FooBar(models.Model):
    permit_edit = limit_to_usergroups.UsergroupsModelField()
    permit_view = limit_to_usergroups.UsergroupsModelField()

Die Rechte für ein Objekt kann man z.B. so abfragen, mit dabei noch ein Beispiel wie man eine Aussagekräftige Meldung erstellen kann:

Code: Alles auswählen

def edit(request, id):
    foo = FooBar.objects.get(id=id)
    if not limit_to_usergroups.has_permission(poll, permit_edit=request.user):
        msg = _("You have no permission to edit this.")
        if settings.DEBUG:
            verbose_limit_name = limit_to_usergroups.get_verbose_limit_name(foo.permit_edit)
            msg += " (Limited to: %s)" % verbose_limit_name
            messages.error(request, msg)
        return HttpResponseRedirect("foobar)
    ...

Im view kann man z.B. ein Queryset Filtern anhand der Rechte des aktuellen Users:

Code: Alles auswählen

from django_tools import limit_to_usergroups

def view(request):
    queryset = FooBar.objects.all()
    queryset = limit_to_usergroups.filter_permission(queryset, permit_view=request.user)
    ...
Und hier könnte man was erheblich verbessern: Wie kann man Dinge wie has_permission() und filter_permission() direkt an den QuerySet hängen?

Man muß wohl den Model-Manager erweitern. Hab ich versucht, aber mit wenig Erfolg.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hab eine Idee zu einer vielleicht besseren Lösung:

Denn die Aktuelle Lösung hat den Hacken, das man nicht gut mit QuersSet-Methoden die Daten filtern kann. Zwar hab ich dazu ja extra Routinen mit bei gepackt, aber dennoch ist das Unschön.

Nun hab ich die Idee, das man zwar mehrere Datenbank Felder nutzt, aber dennoch in forms das ganze zu einer Selection-Box zusammen fasst.

So hat man dann doch best-of-both-worlds...

Wie dann die Konkrete Realisierung aussehen kann, weiß ich noch nicht. Aber was haltet ihr von so einer Lösung?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Antworten