Blog Spass mit Newforms-Admin - Ganz schnell Widgets zuweisen

In den vergangenen Spass mit Newforms-Admin Beiträgen hab ich immer wieder gezeigt, wie man das Widget (die HTML-Ausgabe) eines Feldes beeinflusst und ändert.

Als Beispiel nochmal ein simples Model, bei dem letztendlich der Titel in großer Schrift ausgegeben werden soll.

from django.db import models

class Foobar(models.Model):
    title = models.CharField(max_length=100)
    text = models.TextField(blank=True)

Also basteln wir uns -- wie gehabt -- eine ModelAdmin-Klasse und darin eine Methode formfield_for_dbfield. Diese durchläuft alle Felder und wenn sie auf den passenden Titel trifft, ändert sie das Widget dazu.

from django.contrib import admin
from django import forms
from django.utils.safestring import mark_safe
from .models import Foobar

class BigTitleWidget(forms.widgets.Input):
    def render(self, name, value, attrs=None):
        field = '<input name="%s" value="%s" style="font-size:1.5em"/>' % (name, value)
        return mark_safe(field)

class FoobarAdmin(admin.ModelAdmin):
    def formfield_for_dbfield(self, db_field, **kwargs):
        field = super(FoobarAdmin, self).formfield_for_dbfield(db_field, **kwargs)
        if db_field.name == "title":
            field.widget = BigTitleWidget()
        return field

admin.site.register(Foobar, FoobarAdmin)

Aber ist das nicht super hässlich? Irgendwann bin ich mal über einen Codeblock von Jannis gestolpert und hab gesehen, dass die ModelAdmin-Klasse ein Attribut form besitzt, dass das automatisch generierte ModelForm mit einem eigenen überschreiben kann. Hey, und das ist sogar dokumentiert.

from django.contrib import admin
from django import forms
from django.utils.safestring import mark_safe
from .models import Foobar

class BigTitleWidget(forms.widgets.Input):
    def render(self, name, value, attrs=None):
        field = '<input name="%s" value="%s" style="font-size:1.5em"/>' % (name, value)
        return mark_safe(field)

class FoobarForm(forms.ModelForm):
    title = forms.CharField(widget=BigTitleWidget())

class FoobarAdmin(admin.ModelAdmin):
    form = FoobarForm

admin.site.register(Foobar, FoobarAdmin)

Das ist doch viel schöner! :-)

Also nie wieder formfield_for_dbfield? Nicht ganz, denn innerhalb des ModelForms hat man keinen Zugriff auf die anderen Parameter des aktuellen Admin-Views. Will man dem Widget weitere Parameter übergeben (wie z.B. die aktuelle User-ID, hier erklärt, führt der Weg weiterhin über formfield_for_dbfield.