Django-Admin: CharField as TextArea

DjangoDjango Admin

Django Problem Overview


I have

class Cab(models.Model):
    name  = models.CharField( max_length=20 )
    descr = models.CharField( max_length=2000 )

class Cab_Admin(admin.ModelAdmin):
    ordering     = ('name',)
    list_display = ('name','descr', )
    # what to write here to make descr using TextArea?

admin.site.register( Cab, Cab_Admin )

how to assign TextArea widget to 'descr' field in admin interface?

upd:
In Admin interface only!

Good idea to use ModelForm.

Django Solutions


Solution 1 - Django

You will have to create a forms.ModelForm that will describe how you want the descr field to be displayed, and then tell admin.ModelAdmin to use that form. For example:

from django import forms
class CabModelForm( forms.ModelForm ):
    descr = forms.CharField( widget=forms.Textarea )
    class Meta:
        model = Cab

class Cab_Admin( admin.ModelAdmin ):
    form = CabModelForm

The form attribute of admin.ModelAdmin is documented in the official Django documentation. Here is one place to look at.

Solution 2 - Django

For this case, the best option is probably just to use a TextField instead of CharField in your model. You can also override the formfield_for_dbfield method of your ModelAdmin class:

class CabAdmin(admin.ModelAdmin):
    def formfield_for_dbfield(self, db_field, **kwargs):
        formfield = super(CabAdmin, self).formfield_for_dbfield(db_field, **kwargs)
        if db_field.name == 'descr':
            formfield.widget = forms.Textarea(attrs=formfield.widget.attrs)
        return formfield

Solution 3 - Django

Ayaz has pretty much spot on, except for a slight change(?!):

class MessageAdminForm(forms.ModelForm):
    class Meta:
        model = Message
        widgets = {
            'text': forms.Textarea(attrs={'cols': 80, 'rows': 20}),
        }

class MessageAdmin(admin.ModelAdmin):
    form = MessageAdminForm
admin.site.register(Message, MessageAdmin)

So, you don't need to redefine a field in the ModelForm to change it's widget, just set the widgets dict in Meta.

Solution 4 - Django

You don't need to create the form class yourself:

from django.contrib import admin
from django import forms

class MyModelAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, **kwargs):
        kwargs['widgets'] = {'descr': forms.Textarea}
        return super().get_form(request, obj, **kwargs)

admin.site.register(MyModel, MyModelAdmin)

See ModelAdmin.get_form.

Solution 5 - Django

You can subclass your own field with needed formfield method:

class CharFieldWithTextarea(models.CharField):
    
    def formfield(self, **kwargs):
        kwargs.update({"widget": forms.Textarea})
        return super(CharFieldWithTextarea, self).formfield(**kwargs)

This will take affect on all generated forms.

Solution 6 - Django

If you are trying to change the Textarea on admin.py, this is the solution that worked for me:

from django import forms
from django.contrib import admin
from django.db import models
from django.forms import TextInput, Textarea

from books.models import Book

class BookForm(forms.ModelForm):
	description = forms.CharField( widget=forms.Textarea(attrs={'rows': 5, 'cols': 100}))
	class Meta:
		model = Book

class BookAdmin(admin.ModelAdmin):
    form = BookForm

admin.site.register(Book, BookAdmin)

If you are using a MySQL DB, your column length will usually be autoset to 250 characters, so you will want to run an ALTER TABLE to change the length in you MySQL DB, so that you can take advantage of the new larger Textarea that you have in you Admin Django site.

Solution 7 - Django

Instead of a models.CharField, use a models.TextField for descr.

Solution 8 - Django

You can use models.TextField for this purpose:

class Sample(models.Model):
    field1 = models.CharField(max_length=128)
    field2 = models.TextField(max_length=1024*2)   # Will be rendered as textarea

Solution 9 - Django

Wanted to expand on Carl Meyer's answer, which works perfectly till this date.

I always use TextField instead of CharField (with or without choices) and impose character limits on UI/API side rather than at DB level. To make this work dynamically:

from django import forms
from django.contrib import admin


class BaseAdmin(admin.ModelAdmin):
    """
    Base admin capable of forcing widget conversion
    """
    def formfield_for_dbfield(self, db_field, **kwargs):
        formfield = super(BaseAdmin, self).formfield_for_dbfield(
            db_field, **kwargs)

        display_as_charfield = getattr(self, 'display_as_charfield', [])
        display_as_choicefield = getattr(self, 'display_as_choicefield', [])

        if db_field.name in display_as_charfield:
            formfield.widget = forms.TextInput(attrs=formfield.widget.attrs)
        elif db_field.name in display_as_choicefield:
            formfield.widget = forms.Select(choices=formfield.choices,
                                            attrs=formfield.widget.attrs)

        return formfield

I have a model name Post where title, slug & state are TextFields and state has choices. The admin definition looks like:

@admin.register(Post)
class PostAdmin(BaseAdmin):
    list_display = ('pk', 'title', 'author', 'org', 'state', 'created',)
    search_fields = [
        'title',
        'author__username',
    ]
    display_as_charfield = ['title', 'slug']
    display_as_choicefield = ['state']

Thought others looking for answers might find this useful.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmaxpView Question on Stackoverflow
Solution 1 - DjangoayazView Answer on Stackoverflow
Solution 2 - DjangoCarl MeyerView Answer on Stackoverflow
Solution 3 - DjangoGezimView Answer on Stackoverflow
Solution 4 - Djangox-yuriView Answer on Stackoverflow
Solution 5 - DjangoAlex KoshelevView Answer on Stackoverflow
Solution 6 - DjangoAaron LelevierView Answer on Stackoverflow
Solution 7 - DjangomipadiView Answer on Stackoverflow
Solution 8 - Djangovk-codeView Answer on Stackoverflow
Solution 9 - DjangotarequehView Answer on Stackoverflow