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?


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)

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}}

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

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 %}

¡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.


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.


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.


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)

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",)}

¡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'])

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)

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 .


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í .


-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.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.