Redimensionar campos en Django Admin

Django tiende a llenar un espacio horizontal al agregar o editar entradas en el administrador, pero, en algunos casos, es un verdadero desperdicio de espacio cuando, por ejemplo, se edita un campo de fecha, de 8 caracteres de ancho, o un campo de caracteres, también 6 o 8 caracteres de ancho, y luego el cuadro de edición sube a 15 o 20 caracteres.

¿Cómo puedo decirle al administrador qué ancho debe ser un cuadro de texto, o la altura de un cuadro de edición de TextField?

Debe utilizar ModelAdmin.formfield_overrides .

Es bastante fácil – en admin.py , define:

 class YourModelAdmin(admin.ModelAdmin): formfield_overrides = { models.CharField: {'widget': TextInput(attrs={'size':'20'})}, models.TextField: {'widget': Textarea(attrs={'rows':4, 'cols':40})}, } admin.site.register(YourModel, YourModelAdmin) 

No olvide que debe importar las clases apropiadas, en este caso:

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

Puede establecer atributos HTML arbitrarios en un widget utilizando su propiedad “attrs” .

Puedes hacer esto en el administrador de Django usando formfield_for_dbfield:

 class MyModelAdmin(admin.ModelAdmin): def formfield_for_dbfield(self, db_field, **kwargs): field = super(ContentAdmin, self).formfield_for_dbfield(db_field, **kwargs) if db_field.name == 'somefield': field.widget.attrs['class'] = 'someclass ' + field.widget.attrs.get('class', '') return field 

o con una subclase de Widget personalizada y el diccionario formfield_overrides :

 class DifferentlySizedTextarea(forms.Textarea): def __init__(self, *args, **kwargs): attrs = kwargs.setdefault('attrs', {}) attrs.setdefault('cols', 80) attrs.setdefault('rows', 5) super(DifferentlySizedTextarea, self).__init__(*args, **kwargs) class MyModelAdmin(admin.ModelAdmin): formfield_overrides = { models.TextField: {'widget': DifferentlySizedTextarea}} 

Para cambiar el ancho de un campo específico.

Hecho a través de ModelAdmin.get_form :

 class YourModelAdmin(admin.ModelAdmin): def get_form(self, request, obj=None, **kwargs): form = super(YourModelAdmin, self).get_form(request, obj, **kwargs) form.base_fields['myfield'].widget.attrs['style'] = 'width: 45em;' return form 

Una opción rápida y sucia es simplemente proporcionar una plantilla personalizada para el modelo en cuestión.

Si crea una plantilla llamada admin///change_form.html , el administrador usará esa plantilla en lugar de la predeterminada. Es decir, si tienes un modelo llamado Person en una aplicación llamada people , admin/people/person/change_form.html una plantilla llamada admin/people/person/change_form.html .

Todas las plantillas de administrador tienen un bloque de id_ que puede anular para colocar cosas en el , y la pieza final del rompecabezas es el hecho de que cada campo tiene una identificación HTML de id_ .

Entonces, podrías poner algo como lo siguiente en tu plantilla:

 {% extends "admin/change_form.html" %} {% block extrahead %} {{ block.super }}  {% endblock %} 

Si desea cambiar los atributos en una instancia por campo, puede agregar la propiedad “attrs” directamente en las entradas de su formulario.

por ejemplo:

 class BlogPostForm(forms.ModelForm): title = forms.CharField(label='Title:', max_length=128) body = forms.CharField(label='Post:', max_length=2000, widget=forms.Textarea(attrs={'rows':'5', 'cols': '5'})) class Meta: model = BlogPost fields = ('title', 'body') 

La propiedad “attrs” básicamente pasa a lo largo del marcado HTML que ajustará el campo de formulario. Cada entrada es una tupla del atributo que desea anular y el valor con el que desea anularla. Puede ingresar tantos atributos como desee siempre que separe cada tupla con una coma.

La mejor manera que encontré es algo como esto:

 class NotificationForm(forms.ModelForm): def __init__(self, *args, **kwargs): super(NotificationForm, self).__init__(*args, **kwargs) self.fields['content'].widget.attrs['cols'] = 80 self.fields['content'].widget.attrs['rows'] = 15 self.fields['title'].widget.attrs['size'] = 50 class Meta: model = Notification 

Es mucho mejor para ModelForm que anular campos con diferentes widgets, ya que conserva los atributos name y help_text y también los valores predeterminados de los campos del modelo, por lo que no tiene que copiarlos en su formulario.

Tuve un problema similar con TextField. Estoy usando Django 1.0.2 y quería cambiar el valor predeterminado para “filas” en el área de texto asociada. formfield_overrides no existe en esta versión. La anulación de formfield_for_dbfield funcionó pero tuve que hacerlo para cada una de mis subclases ModelAdmin o daría como resultado un error de recursión. Finalmente, encontré que agregar el siguiente código a models.py funciona:

 from django.forms import Textarea class MyTextField(models.TextField): #A more reasonably sized textarea def formfield(self, **kwargs): kwargs.update( {"widget": Textarea(attrs={'rows':2, 'cols':80})} ) return super(MyTextField, self).formfield(**kwargs) 

Luego use MyTextField en lugar de TextField cuando defina sus modelos. Lo adapté de esta respuesta a una pregunta similar.

Está bien descrito en las preguntas frecuentes de Django :

P: ¿Cómo cambio los atributos de un widget en un campo de mi modelo?

A: Reemplace el campo_campo_for_dbfield en la clase ModelAdmin / StackedInline / TabularInline

 class MyOtherModelInline(admin.StackedInline): model = MyOtherModel extra = 1 def formfield_for_dbfield(self, db_field, **kwargs): # This method will turn all TextFields into giant TextFields if isinstance(db_field, models.TextField): return forms.CharField(widget=forms.Textarea(attrs={'cols': 130, 'rows':30, 'class': 'docx'})) return super(MyOtherModelInline, self).formfield_for_dbfield(db_field, **kwargs) 

Siempre puede establecer el tamaño de sus campos en una hoja de estilo personalizada y decirle a Django que use eso para su clase ModelAdmin:

 class MyModelAdmin(ModelAdmin): class Media: css = {"all": ("my_stylesheet.css",)} 

para 1.6, usando formularios tuve que especificar los atributos del área de texto dentro del campo de caracteres:

 test1 = forms.CharField(max_length=400, widget=forms.Textarea( attrs={'rows':'2', 'cols': '10'}), initial='', help_text=helptexts.helptxt['test']) 

La misma respuesta que msdin pero con TextInput en lugar de TextArea:

 from django.forms import TextInput class ShortTextField(models.TextField): def formfield(self, **kwargs): kwargs.update( {"widget": TextInput(attrs={'size': 10})} ) return super(ShortTextField, self).formfield(**kwargs) 

Aquí hay una solución simple pero flexible. Utilice un formulario personalizado para anular algunos widgets.

 # models.py class Elephant(models.Model): name = models.CharField(max_length=25) age = models.IntegerField() # forms.py class ElephantForm(forms.ModelForm): class Meta: widgets = { 'age': forms.TextInput(attrs={'size': 3}), } # admin.py @admin.register(Elephant) class ElephantAdmin(admin.ModelAdmin): form = ElephantForm 

Los widgets dados en ElephantForm reemplazarán los predeterminados. La clave es la representación de cadena del campo. Los campos no especificados en el formulario utilizarán el widget predeterminado.

Tenga en cuenta que aunque age es un campo IntegerField , podemos usar el widget TextInput , porque a diferencia de NumberInput , TextInput acepta el atributo size .

Esta solución se describe en este artículo .

Si está trabajando con un campo ForeignKey que involucra opciones / opciones / un menú desplegable, puede anular formfield_for_foreignkey en la instancia de administrador:

 class YourNewAdmin(admin.ModelAdmin): ... def formfield_for_foreignkey(self, db_field, request, **kwargs): if db_field.name == 'your_fk_field': """ For your FK field of choice, override the dropdown style """ kwargs["widget"] = django.forms.widgets.Select(attrs={ 'style': 'width: 250px;' }) return super().formfield_for_foreignkey(db_field, request, **kwargs) 

Más información sobre este patrón aquí y aquí .