Django Vormund https://github.com/lukaszb/django-guardian ist eine wirklich gut geschriebene Object-Level-Permissions-App; und ich habe tatsächlich nachgelesen und verwendet eine ganze Reihe von anderen Django Object-Level-Permissions-App in verschiedenen Django-Projekten.
In einem aktuellen Projekt, das ich arbeite, habe ich beschlossen, django Guardian zu verwenden, aber ich habe ein Modell-Design-Frage in Bezug auf die Vor- und Nachteile von zwei möglichen Ansätzen und ihre jeweiligen Auswirkungen auf die Leistung von Sql-Abfragen: -
-
mit
django.contrib.auth.models.Group
und erweitern diese auf die Modelle meiner benutzerdefinierten Organisationsanwendung; oder -
mit
django.contrib.auth.models.User
stattdessen ein m2m-Feld für jeden der Organisationstypen in meiner Organisations-App zu erstellen.
Ansatz 1
# Organisation app's models.py
from django.contrib.auth.models import Group
class StudentClass(models.Model):
name = models.CharField('Class Name', max_length=255)
groups = models.ManyToManyField(Group, blank=True)
size = models.IntegerField('Class Size', blank=True)
class SpecialInterestGroup(models.Model):
name = models.CharField('Interest Group Name', max_length=255)
groups = models.ManyToManyField(Group, blank=True)
description = models.TextField('What our group does!', blank=True)
class TeachingTeam(models.Model):
name = models.CharField('Teacher Team Name', max_length=255)
groups = models.ManyToManyField(Group, blank=True)
specialization = models.TextField('Specialty subject matter', blank=True)
Bei diesem Ansatz wird beim ersten Hinzufügen eines Benutzers zu einer Gruppe (django group) das Gruppenobjekt erstellt und ebenfalls einer dieser 3 Klassen zugeordnet, wenn das Gruppenobjekt noch nicht zu der Klasse gehört, zu der es hinzugefügt wird.
Dies bedeutet, dass jedes StudentClass-Objekt, sc_A
, sc_B
usw., können möglicherweise viele Gruppen enthalten.
Das bedeutet, dass ich feststellen muss, ob ein bestimmter Benutzer (z. B. myuser
) zu einer bestimmten Organisation gehört, muss ich alle Gruppen abfragen, denen der Benutzer angehört, und zwar über groups_myuser_belongto = myuser.groups
und dann alle Gruppen abfragen, die mit der Organisation verbunden sind, an der ich interessiert bin, über groups_studentclass = sc_A.groups.all()
und da ich jetzt 2 Listen habe, die ich vergleichen muss, kann ich Folgendes tun set(groups_myuser_belongto) && set(groups_studentclass)
die eine neue Menge zurückgibt, die 1 oder mehrere Gruppen enthalten kann, die sich überschneiden. Wenn es 1 oder mehr Gruppen gibt, myuser
ist in der Tat ein Mitglied von sc_A
.
Dieses Modelldesign bedeutet also, dass ich viel Mühe (und zusätzliche Abfragen) aufwenden muss, nur um herauszufinden, ob ein Benutzer zu einer Organisation gehört.
Und der Grund, warum ich m2m zu Gruppen verwende, ist, um die Gruppenebene Berechtigungsfunktionalität zu nutzen, die Django Guardian zur Verfügung stellt.
Ist ein solcher Modellentwurf praktikabel?
Oder ist es besser, wenn ich ein anderes Modell wie dieses nehme?
Ansatz #2
# Organisation app's models.py
from django.contrib.auth.models import User
class StudentClass(models.Model):
name = models.CharField('Class Name', max_length=255)
users = models.ManyToManyField(User, blank=True)
size = models.IntegerField('Class Size', blank=True)
class SpecialInterestGroup(models.Model):
name = models.CharField('Interest Group Name', max_length=255)
users = models.ManyToManyField(User, blank=True)
description = models.TextField('What our group does!', blank=True)
class TeachingTeam(models.Model):
name = models.CharField('Teacher Team Name', max_length=255)
users = models.ManyToManyField(User, blank=True)
specialization = models.TextField('Specialty subject matter', blank=True)
Dieses Modelldesign macht es mir natürlich sehr leicht, zu überprüfen, ob ein Benutzerobjekt zu einer bestimmten Organisation gehört oder nicht. Alles was ich tun muss, um herauszufinden, ob ein Benutzer john
ist Teil eines TeachingTeams maths_teachers
oder nicht, ist zu prüfen:
user = User.objects.get(username='john')
maths_teachers = TeachingTeam.objects.get(name='Maths teachers')
if user in maths_teachers.users.all():
print "Yes, this user is in the Maths teachers organization!"
Dieses Modell impliziert jedoch, dass wenn ich ein Benutzerobjekt zu einer Gruppe hinzufüge (erinnern Sie sich daran, dass ich die Gruppenberechtigungsfunktion von django guardian verwenden möchte), muss ich sicherstellen, dass die save()
Aufruf fügt das Benutzerobjekt in eine Gruppe "Mathematiklehrer" in django.contrib.auth.models.Group
UND in meine Gewohnheit TeachingTeam
Objekt "Mathelehrer" der Klasse. Und das fühlt sich nicht sehr DRY an, ganz zu schweigen davon, dass ich irgendwie sicherstellen muss, dass die Speicheraufrufe in beiden Modellen in einer einzigen transaction
.
Gibt es einen besseren Weg, um meine Modelle angesichts dieser Anwendungsfall/Anforderung zu entwerfen - verwenden Sie django Gruppen und dennoch bieten eine Möglichkeit, "erweitern" die django's native Gruppe Funktionalität (fast wie wie wir django's Benutzer-Modell mit einem "Benutzerprofil app" erweitern)?