Змініть розмір полів у Django Admin


108

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

Як я можу сказати адміністратору, якою має бути ширина текстового поля або висота поля редагування TextField?


9
Очевидно, ви забули це зробити в цьому випадку. Більше двох років потому. =)
casperОдин

Проект викрали, і мені не довелося деякий час бачити код. Я можу розпочати новий проект наступного місяця, тож, можливо, я повторю це: D
Андор

Відповіді:


210

Ви повинні використовувати 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)

1
Це саме те, що я шукав без необхідності робити якісь смішні налаштування шаблонів. Дякую!
Кріс,

2
Зауважте, що це не буде працювати, якщо filter_horizontalабо filter_verticalвстановлено для відповідних полів у YourModelAdmin. Я витратив деякий час, щоб розібратися в цьому.
Денніс Голомазов

Чи є щось у цьому у формі? Я не знайшов способу встановити атрибут attrs для всіх Textareas.
Джуліан

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

або зі спеціальним підкласом віджетів та словником 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

На мою думку, це найкраща відповідь, оскільки вона дозволяє змінювати окремі поля, не створюючи нової форми.
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 під час визначення своїх моделей. Я адаптував це з цієї відповіді на подібне запитання.


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)

Коли я використовую цю техніку, довідковий текст не з’явиться, а якщо це TabularInline, заголовок стовпця стає "None".
Стівен Т. Снайдер

1
Це не дуже вдалий підхід, оскільки ви витираєте всі інші налаштування на CharField. Наприклад, за замовчуванням він розумно виявить, чи потрібно обов'язково вводити поле форми, але цей код знищує це. Натомість слід встановити віджет на значення, повернене вашим супер () викликом.
Серін

5

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

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

найкраща відповідь! відсутність перешкод із формами поля та атрибутами (та можливими побічними ефектами), лише файл css, який може - за наявності існуючих ідентифікаторів / класів у формах адміністратора django - легко націлити лише на деякі, а то й усі поля. великий вгору!
бензцзі

2

для 1.6, використовуючи форми, я повинен був вказати атрибути textarea всередині charfield:

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в інстанції адміністратора:

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

Якщо ви бажаєте редагувати лише певний розмір полів, ви можете скористатися цим.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.