onurmatik
onurmatik

Reputation: 5285

Django Admin - Overriding the widget of a custom form field

I have a custom TagField form field.

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

As seen above, it uses a TextInput form field widget. But in admin I would like it to be displayed using Textarea widget. For this, there is formfield_overrides hook but it does not work for this case.

The admin declaration is:

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

This has no effect on the form field widget and tags are still rendered with a TextInput widget.

Any help is much appreciated.

--
omat

Upvotes: 36

Views: 61484

Answers (4)

Murat Çorlu
Murat Çorlu

Reputation: 8545

You can override field widgets by extending the Meta class of a ModelForm since Django 1.2:

from django import forms
from django.contrib import admin


class ProductAdminForm(forms.ModelForm):
    class Meta:
        model = Product
        fields = '__all__'  # edit: django >= 1.8
        widgets = {
            'tags': admin.widgets.AdminTextareaWidget
        }


class ProductAdmin(admin.ModelAdmin):
    form = ProductAdminForm

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

Upvotes: 43

C.K.
C.K.

Reputation: 5508

For a specific field not a kind of fields I use:

Django 2.1.7

class ProjectAdminForm(forms.ModelForm):
    class Meta:
        model = Project
        fields = '__all__'
        widgets = {
            'project_description': forms.Textarea(attrs={'cols': 98})
        }
class ProjectAdmin(admin.ModelAdmin):
    form = ProjectAdminForm

Thanks, @Murat Çorlu

Upvotes: 7

Matthew Schinckel
Matthew Schinckel

Reputation: 35619

The django admin uses custom widgets for many of its fields. The way to override fields is to create a Form for use with the ModelAdmin object.

# 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()

Then, in your ModelAdmin object, you specify the form:

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

class ProductAdmin(admin.ModelAdmin):
    form = ProductAdminForm

admin.site.register(Product, ProductAdmin)

You can also override the queryset at this time: to filter objects according to another field in the model, for instance (since limit_choices_to cannot handle this)

Upvotes: 52

Andrey Fedoseev
Andrey Fedoseev

Reputation: 5382

Try to change your field like this:

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

This would allow to use the widget which comes from **kwargs. Otherwise your field will always use form.TextInput widget.

Upvotes: 3

Related Questions