Изменить размер полей в Django Admin

109

Django имеет тенденцию заполнять горизонтальное пространство при добавлении или редактировании записей в админке, но в некоторых случаях это настоящая трата места, например, при редактировании поля даты шириной 8 символов или CharField, также 6 или 8 шириной символов, а затем поле редактирования увеличивается до 15 или 20 символов.

Как я могу сказать администратору, какой ширины должно быть текстовое поле или высоту поля редактирования TextField?

Андор
источник
9
Очевидно, в данном случае вы забыли это сделать. Более двух лет спустя. =)
casperOne
От проекта отказались, и я какое-то время не видел кода. Я могу начать новый проект в следующем месяце, так что, может быть, я увижу это снова: D
Андор

Ответы:

211

Вы должны использовать ModelAdmin.formfield_overrides .

Это довольно просто - в admin.py, определите:

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
источник
1
Это было именно то, что я искал, без необходимости вносить некоторые нелепые настройки шаблона. Спасибо!
Крис
2
Обратите внимание, что это не будет работать, если filter_horizontalили filter_verticalустановлено для соответствующих полей в YourModelAdmin. Я потратил некоторое время, чтобы понять это.
Денис Голомазов
Есть ли что-нибудь для этого в форме? Я не нашел способа установить атрибут attrs для всех текстовых областей.
Джулиан
1
Я использовал только models.TextField: {'widget': Textarea(attrs={'rows':4})}но и ширина стала меньше.
Smit Johnth
По-видимому, трудно иметь их одного размера.
Sören
45

Вы можете установить произвольные атрибуты HTML для виджета, используя его свойство "attrs" .

Вы можете сделать это в админке Django, используя 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

или с настраиваемым подклассом Widget и словарем 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}}
Карл Мейер
источник
30

Чтобы изменить ширину определенного поля.

Сделано через 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
источник
На мой взгляд, это лучший ответ, поскольку он позволяет изменять отдельные поля без необходимости создавать новую форму.
rbennell
21

Быстрый и грязный вариант - просто предоставить собственный шаблон для рассматриваемой модели.

Если вы создаете шаблон с именем, admin/<app label>/<class name>/change_form.htmlадминистратор будет использовать этот шаблон вместо шаблона по умолчанию. То есть, если у вас есть модель с именем Personв приложении с именем people, вы должны создать шаблон с именем admin/people/person/change_form.html.

Во всех шаблонах администратора есть extraheadблок, который вы можете переопределить, чтобы поместить что-то в него <head>, и последний кусок головоломки - это тот факт, что каждое поле имеет HTML-идентификатор id_<field-name>.

Итак, вы можете поместить в свой шаблон что-то вроде следующего:

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

{% block extrahead %}
  {{ block.super }}
  <style type="text/css">
    #id_my_field { width: 100px; }
  </style>
{% endblock %}
якобианин
источник
Спасибо! Это и ответ alanjds очень полезны для изменения макета в интерфейсе администратора для каждого поля, а не для каждого типа поля.
nealmcb
10

Если вы хотите изменить атрибуты для каждого экземпляра поля, вы можете добавить свойство attrs непосредственно в записи формы.

например:

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

Свойство "attrs" в основном передает разметку HTML, которая корректирует поле формы. Каждая запись представляет собой кортеж атрибута, который вы хотите переопределить, и значение, которое вы хотите переопределить. Вы можете ввести столько атрибутов, сколько захотите, при условии, что вы разделяете каждый кортеж запятой.

Джонатан
источник
IMO - лучший способ изменить только одно поле, а не все TextInput-виджеты сразу (как принятый ответ)
ascripter
7

Лучший способ, который я нашел, выглядит примерно так:

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

Для ModelForm это намного лучше, чем переопределение полей с помощью различных виджетов, поскольку он сохраняет nameи help_textатрибуты, а также значения по умолчанию для полей модели, поэтому вам не нужно копировать их в свою форму.

Курчак
источник
7

У меня была аналогичная проблема с TextField. Я использую Django 1.0.2 и хочу изменить значение по умолчанию для «строк» ​​в связанной текстовой области. formfield_overrides не существует в этой версии. Переопределение formfield_for_dbfield сработало, но мне пришлось сделать это для каждого из моих подклассов ModelAdmin, иначе это привело бы к ошибке рекурсии. В конце концов, я обнаружил, что добавление приведенного ниже кода в models.py работает:

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)

Затем используйте MyTextField вместо TextField при определении ваших моделей. Я адаптировал его из этого ответа на аналогичный вопрос.

msdin
источник
5

Это хорошо описано в FAQ по Django :

В: Как мне изменить атрибуты виджета в поле в моей модели?

A: Переопределите поле formfield_for_dbfield в классе 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
источник
Когда я использую эту технику, текст справки не появляется, а если это TabularInline, заголовок столбца становится «Нет».
Стивен Т. Снайдер
1
Это не лучший подход, поскольку вы удаляете все остальные настройки в CharField. Например, по умолчанию он разумно определяет, должно ли поле формы быть обязательным, но этот код разрушает это. Вместо этого вы должны установить виджет на значение, возвращаемое вашим вызовом super ().
Cerin
5

Вы всегда можете установить размеры полей в настраиваемой таблице стилей и указать Django использовать это для вашего класса ModelAdmin:

class MyModelAdmin(ModelAdmin):
    class Media:
        css = {"all": ("my_stylesheet.css",)}
Гонсало
источник
лучший ответ! не возиться с полями формы и атрибутами (и возможными побочными эффектами), только файл css, который может - с существующими идентификаторами / классами в формах администратора django - легко ориентироваться только на некоторые или даже все поля. большой вверх!
benzkji
2

для 1.6, используя формы, мне пришлось указать атрибуты текстового поля внутри поля char:

test1 = forms.CharField(max_length=400, widget=forms.Textarea( attrs={'rows':'2', 'cols': '10'}),  initial='', help_text=helptexts.helptxt['test'])
Дедду
источник
1

Тот же ответ, что и msdin, но с TextInput вместо 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

Вот простое, но гибкое решение. Используйте настраиваемую форму, чтобы переопределить некоторые виджеты.

# 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

Представленные виджеты ElephantFormзаменят виджеты по умолчанию. Ключ - это строковое представление поля. Поля, не указанные в форме, будут использовать виджет по умолчанию.

Обратите внимание, что, хотя ageэто, IntegerFieldмы можем использовать TextInputвиджет, потому что, в отличие от NumberInput, TextInputпринимает sizeатрибут.

Это решение описано в этой статье .

Ээрик Свен Пуудист
источник
0

Если вы работаете с полем ForeignKey, которое включает варианты выбора / параметры / раскрывающееся меню, вы можете переопределить formfield_for_foreignkeyв экземпляре Admin:

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)

Подробнее об этом шаблоне здесь и здесь .

мих
источник
-1

И еще один пример:

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

Если вы хотите отредактировать только поля определенного размера, вы можете использовать это.

Мевака
источник