Spass mit Newforms-Admin - Automatische Felder
Geschrieben 3 Monate, 1 Woche zuvor
Im letzten Artikel Rowlevel-Permissions ging es darum, wie man Einträge nur vom Benutzer selber bearbeiten lassen kann. Wer den Artikel verfolgt und aufgebaut hat, wird festgestellt haben, dass die ganze Sache einen gewaltigen Haken hatte:
In der Detailansicht konnte das Autorenfeld frei definiert werden, sprich Benutzer A konnte sich für Benutzer B ausgeben und umgekehrt. In diesem Artikel geht es darum, dem eingeloggten Autor automatisch den Artikel zuzuweisen.
Holzhammer
Die einfachste Lösung ist: Zeige das Autorenfeld gar nicht erst an und weise beim Speichern des Artikels dem Autorenfeld den eingeloggten User zu. Das Ganze ist schnell geschehen. Ähnlich wie die "newforms save()" Methode stellt auch ModelAdmin eine Methode zum Überschreiben zur Verfügung:
class EntryAdmin(admin.ModelAdmin): # Autorenfeld ausblenden (mit #7937 geht das irgendwann mal einfacher) # #7937: http://code.djangoproject.com/ticket/7973 fields = ( 'title', 'content', ) # Formular valdidieren, Autor setzen und speichern def save_form(self, request, form, change): instance = form.save(commit=False) # Nur bei neuen Artikeln den User setzen if not change: instance.author = request.user return instance
Fertig ist die ganze Geschichte. Schnell, sicher und kaum zu überlisten.
Nicht ganz so krass
Vielleicht ist das aber auch schon einen Schritt zu weit. In meinem aktuellen Projekt möchte ich es trotzdem dem Benutzer überlassen, den Autor zu setzen, allerdings mit einer Kleinigkeit: Der aktuelle Benutzer soll in der Liste schon vorausgewählt sein.
Das Ganze ist ein wenig mehr "tricky". In ModelAdmin gibt es wiederrum eine Methode, die vor der Anzeige der Felder aufgerufen wird und mit der man ihr Verhalten und Aussehen (Widgets) beeinflussen kann: formfield_for_dbfield.
class EntryAdmin(admin.ModelAdmin): def formfield_for_dbfield(self, db_field, **kwargs): field = super(EntryAdmin, self).formfield_for_dbfield(db_field, **kwargs) # Autorenfeld hat als Vorauswahl den aktuellen User if db_field.name == "author": field.initial = request.user.pk return field
In dieser Methode prüfen wir, ob das aktuelle Feld unser "Autorenfeld" ist, dann wird ihm als Startwert (initial) der aktuelle User zugewiesen.
Nächster Haken: Der obige Code funktioniert nicht, in der Methode formfield_for_dbfield hat man keinen Zugriff auf das request-Objekt. Ein wenig Patching muss her:
class EntryAdmin(admin.ModelAdmin): def add_view(self, request, *args, **kwargs): self._request = request return super(EntryAdmin, self).add_view(request, *args, **kwargs) def change_view(self, request, *args, **kwargs): self._request = request return super(EntryAdmin, self).change_view(request, *args, **kwargs) def formfield_for_dbfield(self, db_field, **kwargs): field = super(EntryAdmin, self).formfield_for_dbfield(db_field, **kwargs) # Autorenfeld hat als Vorauswahl den aktuellen User if db_field.name == "author": field.initial = self._request.user.pk return field
Glücklicherweise ist ModelAdmin flexibel genug, das Problem zu lösen. Die Methoden add_view und change_view werden vor der Anzeige des Formulares aufgerufen und beiden steht das Request-Objekt zur Verfügung. Das ist genau der richtige Ort, das Request-Objekt als globale Eigenschaft (self._request) der Klasse zuzuweisen.
Somit kann man in der formfield-Methode einfach auf das "globale" Request-Objekt zugreifen und mit den paar Handgriffen ist der Benutzer in der Autorenliste vorausgewählt.
Mit ein wenig Javascript kann man auch einfach aus diesen beiden Sachen eins machen:
Und nicht vergessen: Auch hier ist es wieder möglich mit Permissions zu arbeiten. So könnte ein Administrator immer den Autor setzen (zweite Variante), wo ein "normaler" User kein Autorenfeld zu Gesicht bekommt und automatisch gesetzt wird (erste Variante).










15:39 Uhr
Das Video ist schön... Wo ist das JS?
Ja, ja ich zerbreche mir selbst den Kopf...
Wiedereinmal ein spitze Artikel. Danke. (Mir war auch nicht bewusst, dass ich endlich auf
requestzugreifen kann.)*nun threadlocals endlich weg werfen kann*
Immer weiter so.
21:29 Uhr
Wunderbar! Habs direkt bei mir eingebaut -- und das JS in jQuery nachgebaut: http://gist.github.com/7323
19:19 Uhr
wie wuerde das denn konkret Ausschauen mit der Kombination von beidem, also Admin bekommt Feld zur auswahl und normaler User nicht?
20:27 Uhr
so gehts, enthaelt aber leider viel redundanten code: