Cambiar el tamaño de los campos en Django Admin

107

Django tiende a llenar el espacio horizontal al agregar o editar entradas en el administrador, pero, en algunos casos, es una verdadera pérdida de espacio, es decir, cuando se edita un campo de fecha, de 8 caracteres de ancho, o un CharField, también de 6 u 8 caracteres de ancho, y luego el cuadro de edición sube a 15 o 20 caracteres.

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

Andor
fuente
9
Obviamente, se olvidó de hacer eso en este caso. Más de dos años después. =)
casperOne
El proyecto se abandonó y no pude ver el código durante un tiempo. Puedo comenzar un nuevo proyecto el próximo mes, así que tal vez vuelva a ver esto: D
Andor

Respuestas:

209

Debe utilizar ModelAdmin.formfield_overrides .

Es bastante fácil admin.py, definir:

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

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)
jki
fuente
1
Esto era exactamente lo que estaba buscando sin tener que hacer algunas personalizaciones de plantilla ridículas. ¡Gracias!
Chris
2
Tenga en cuenta que esto no funcionará si filter_horizontalo filter_verticalestá configurado para los campos correspondientes en YourModelAdmin. Pasé un tiempo para resolver esto.
Dennis Golomazov
¿Hay alguna razón para esto en una forma? No encontré una forma de establecer el atributo attrs para todas las áreas de texto.
Julian
1
Usé solo, models.TextField: {'widget': Textarea(attrs={'rows':4})}pero el ancho también se hizo más pequeño.
Smit Johnth
Es difícil tenerlos del mismo tamaño aparentemente.
Sören
44

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

Puede 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}}
Carl Meyer
fuente
29

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
Alanjds
fuente
En mi opinión, esta es la mejor respuesta, ya que permite cambiar campos individuales sin tener que crear un nuevo formulario.
rbennell
20

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

Si crea una plantilla con nombre admin/<app label>/<class name>/change_form.html, el administrador utilizará esa plantilla en lugar de la predeterminada. Es decir, si tiene un modelo nombrado Personen una aplicación nombrada people, crearía una plantilla llamada admin/people/person/change_form.html.

Todas las plantillas de administración tienen un extraheadbloque que puede anular para colocar cosas en el <head>, y la pieza final del rompecabezas es el hecho de que cada campo tiene una identificación HTML de id_<field-name>.

Entonces, podría poner algo como lo siguiente en su plantilla:

{% extends "admin/change_form.html" %}

{% block extrahead %}
  {{ block.super }}
  <style type="text/css">
    #id_my_field { width: 100px; }
  </style>
{% endblock %}
jacobiano
fuente
¡Gracias! Esto y la respuesta de alanjds son muy útiles para cambiar el diseño en la interfaz de administración por campo, en lugar de por tipo de campo.
nealmcb
10

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 transmite el marcado HTML que ajustará el campo del formulario. Cada entrada es una tupla del atributo que le gustaría anular y el valor con el que le gustaría anularlo. Puede ingresar tantos atributos como desee siempre que separe cada tupla con una coma.

Jonathan
fuente
En mi opinión, la mejor manera de modificar solo un campo y no todos los widgets de entrada de texto a la vez (como lo hace la respuesta aceptada)
ascripter
7

La mejor forma 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 de invalidar campos con diferentes widgets, ya que preserva namey help_textatributos y también los valores por defecto de campos del modelo, por lo que no tiene que copiarlos en el formulario.

Kurczak
fuente
7

Tuve un problema similar con TextField. Estoy usando Django 1.0.2 y quería cambiar el valor predeterminado de 'filas' en el área de texto asociada. formfield_overrides no existe en esta versión. Anular formfield_for_dbfield funcionó, pero tuve que hacerlo para cada una de mis subclases de ModelAdmin o resultaría en un error de recursividad. Finalmente, descubrí 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 al definir sus modelos. Lo adapté de esta respuesta a una pregunta similar.

msdin
fuente
5

Está bien descrito en las preguntas frecuentes de Django :

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

R: Anule el campo formfield_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)
HardQuestions
fuente
Cuando utilizo esta técnica, el texto de ayuda no aparecerá, y si es un TabularInline, el encabezado de la columna se convierte en 'Ninguno'.
Steven T. Snyder
1
Este no es un buen enfoque, ya que está borrando todas las demás configuraciones en CharField. Por ejemplo, de forma predeterminada, detectará de forma inteligente si el campo del formulario debe ser obligatorio o no, pero este código lo destruye. En su lugar, debe configurar el widget en el valor devuelto por su llamada super ().
Cerin
5

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

class MyModelAdmin(ModelAdmin):
    class Media:
        css = {"all": ("my_stylesheet.css",)}
Gonzalo
fuente
¡la mejor respuesta! sin jugar con campos de formulario y atributos (y posibles efectos secundarios), solo un archivo css, que puede, con los identificadores / clases existentes en los formularios de administración de django, apuntar fácilmente solo a algunos, o incluso a todos los campos. grande!
benzkji
2

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

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

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)
dan-klasson
fuente
1

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 proporcionados ElephantFormreemplazarán a 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 agees un IntegerField, podemos usar el TextInputwidget, porque a diferencia del NumberInput, TextInputacepta el sizeatributo.

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

Eerik Sven Puudist
fuente
0

Si está trabajando con un campo ForeignKey que incluye opciones / opciones / un menú desplegable, puede anular formfield_for_foreignkeyen 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í .

mih
fuente
-1

Y un ejemplo más también:

class SecenekInline(admin.TabularInline):
   model = Secenek
   # classes = ['collapse']
   def formfield_for_dbfield(self, db_field, **kwargs):
       field = super(SecenekInline, self).formfield_for_dbfield(db_field, **kwargs)
       if db_field.name == 'harf':
           field.widget = TextInput(attrs={'size':2})
       return field
   formfield_overrides = {
       models.TextField: {'widget': Textarea(attrs={'rows':2})},
   }
   extra = 2

Si desea editar solo un tamaño de campo específico, puede usar esto.

mevaka
fuente