2010-08-12 14 views
22

Ich habe ein benutzerdefiniertes TagField-Formularfeld.Django Admin - Überschreiben des Widgets eines benutzerdefinierten Formularfelds

class TagField(forms.CharField): 
    def __init__(self, *args, **kwargs): 
     super(TagField, self).__init__(*args, **kwargs) 
     self.widget = forms.TextInput(attrs={'class':'tag_field'}) 

Wie oben zu sehen, wird ein TextInput-Formularfeldwidget verwendet. Aber in admin möchte ich es mit Textarea Widget angezeigt werden. Dafür gibt es formfield_overrides Haken, aber es funktioniert nicht für diesen Fall.

Die Admin Erklärung:

class ProductAdmin(admin.ModelAdmin): 
    ... 
    formfield_overrides = { 
     TagField: {'widget': admin.widgets.AdminTextareaWidget}, 
    } 

Dies hat keine Auswirkung auf dem Formularfeld-Widget und tags sind nach wie vor mit einem TextInput- Widget gemacht.

Jede Hilfe wird sehr geschätzt.

-
omat

Antwort

40

Der Django-Administrator verwendet benutzerdefinierte Widgets für viele seiner Felder. Die Methode zum Überschreiben von Feldern besteht darin, ein Formular zur Verwendung mit dem ModelAdmin-Objekt zu erstellen.

# forms.py 

from django import forms 
from django.contrib import admin 

class ProductAdminForm(forms.ModelForm): 
    def __init__(self, *args, **kwargs): 
     super(ProductAdminForm, self).__init__(*args, **kwargs) 
     self.fields['tags'].widget = admin.widgets.AdminTextareaWidget() 

Dann in Ihrem Modeladmin Objekt, geben Sie das Formular:

from django.contrib import admin 
from models import Product 
from forms import ProductAdminForm 

class ProductAdmin(admin.ModelAdmin): 
    form = ProductAdminForm 

admin.site.register(Product, ProductAdmin) 

Sie auch die queryset zu diesem Zeitpunkt außer Kraft setzen kann: Objekte zum Filtern nach einem anderen Feld in dem Modell, zum Beispiel (da limit_choices_to dies nicht verarbeiten kann)

+0

Dies funktionierte nicht für mich, Sie müssen eine Instanz des Widgets übergeben, anstatt die Klasse. Die Instanz funktionierte jedoch perfekt. –

+0

Normalerweise würde ich benutzerdefinierte Admin-Formulare in admin.py erstellen und sie nicht mit forms.py mischen. Dadurch werden Verwechslungen für andere Entwickler vermieden und alle administrationsspezifischen Elemente in derselben .py-Datei gespeichert. – MaestroFJP

+0

Guter Punkt @ MaestroFJP. Genau das habe ich in meinem neueren Code gemacht. Oder haben Sie ein Submodul von forms/admin.py, wenn Sie wirklich komplizierte Formulare haben, und viele von ihnen. –

1

Versuchen Sie, Ihre Feld wie folgt zu ändern:

class TagField(forms.CharField): 
    def __init__(self, *args, **kwargs): 
     self.widget = forms.TextInput(attrs={'class':'tag_field'}) 
     super(TagField, self).__init__(*args, **kwargs) 

Dies würde es ermöglichen das Widget zu verwenden, die aus **kwargs kommt. Ansonsten wird Ihr Feld immer form.TextInput Widget verwenden.

+0

ich habe die Änderung übernommen, aber jetzt werden alle Tagfelder als Textarea gerendert. – omat

+0

bei django.forms.fields der Suche finde ich, dass der richtige Weg, um den Standard-Widget für ein Feld angeben ist: Klasse Tagfield (form.CharField): Widget = forms.TextInput def widget_attrs (self, widget): return {'class': 'tag_field'} Sie haben die '__init__' Methode nicht überschrieben. Versuche dies. –

+0

danke aber immer noch kein glück. Alle Tag-Felder werden als Textarea angezeigt, und zwar nicht nur für ProductAdmin, sondern für den ganzen Admin. – omat

27

Sie Feld Widgets durch die Erweiterung Modelform Meta-Klasse seit Django 1.2 außer Kraft setzen können:

class ProductAdminForm(forms.ModelForm): 
    class Meta: 
     model = Product 
     widgets = { 
      'tags': admin.widgets.AdminTextareaWidget 
     } 

class ProductAdmin(admin.ModelAdmin): 
    form = ProductAdminForm 

https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#overriding-the-default-fields

+3

Beginnend mit Django 1.8 solltest du 'fields = '__all __' zu' Meta' hinzufügen. Vide http://stackoverflow.com/a/28306347/1161025. – maciek