Django стремится заполнять горизонтальное пространство при добавлении или редактировании записей в администраторе, но в некоторых случаях это реальная трата пространства, когда, т.е. редактирование поля даты, 8 символов или CharField, также 6 или 8 символов, а затем поле редактирования увеличивается до 15 или 20 символов.
Как я могу сообщить администратору, насколько широким является текстовое поле или высота поля редактирования TextField?
Вы должны использовать ModelAdmin.formfield_overrides.
Это довольно легко - в admin.py
определить:
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)
Не забывайте, что вы должны импортировать соответствующие классы - в этом случае:
from django.forms import TextInput, Textarea
from django.db import models
Вы можете установить произвольные атрибуты HTML в виджет, используя свойство "attrs" .
Вы можете сделать это в admin 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}}
Чтобы изменить ширину для определенного поля.
Сделано через 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
Быстрая и грязная опция - просто предоставить настраиваемый шаблон для рассматриваемой модели.
Если вы создадите шаблон с именем 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 %}
Если вы хотите изменить атрибуты для экземпляра для каждого поля, вы можете добавить свойство "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, которая будет корректировать поле формы. Каждая запись представляет собой кортеж атрибута, который вы хотите переопределить, и значение, которое вы хотели бы переопределить. Вы можете ввести столько атрибутов, сколько хотите, если вы разделяете каждый кортеж запятой.
У меня была аналогичная проблема с TextField. Я использую Django 1.0.2 и хочу изменить значение по умолчанию для 'rows' в связанной текстовой области. formfield_overrides не существует в этой версии. Overriding 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 при определении ваших моделей. Я адаптировал его из этого ответа к аналогичному вопросу.
Лучший способ, который я нашел, это что-то вроде этого:
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
, а также значения по умолчанию для полей модели, поэтому вам не нужно копировать их в вашу форму.
Вы всегда можете задавать размеры полей в пользовательской таблице стилей и указывать Django на использование этого класса ModelAdmin:
class MyModelAdmin(ModelAdmin):
class Media:
css = {"all": ("my_stylesheet.css",)}
Это хорошо описано в FAQ по Django:
Q: Как изменить атрибуты виджета в поле в моей модели?
A: Переопределить поле formfield_for_db в классе 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)
для 1.6, используя формы, я должен был указать атрибуты textarea внутри charfield:
test1 = forms.CharField(max_length=400, widget=forms.Textarea( attrs={'rows':'2', 'cols': '10'}), initial='', help_text=helptexts.helptxt['test'])
TextField
.
Тот же ответ, что и 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)
Если вы работаете с полем 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)
Вот простое, но гибкое решение. Используйте пользовательскую форму, чтобы переопределить некоторые виджеты.
# 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
.
Это решение описано в этой статье.