Django a tendance à remplir l’espace horizontal lors de l’ajout ou de la modification d’entrées dans l’administrateur, mais représente dans certains cas un réel gaspillage d’espace lorsque, par exemple, la modification d’un champ de date, d’une largeur de 8 caractères, ou d’un champChamp, ainsi que 6 ou 8 large de caractères, puis la zone d'édition va jusqu'à 15 ou 20 caractères.
Comment puis-je dire à l'administrateur de la largeur d'une zone de texte ou de la hauteur d'une boîte d'édition TextField?
Vous devez utiliser ModelAdmin.formfield_overrides .
C'est assez facile - dans admin.py
, définissez:
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)
N'oubliez pas que vous devez importer les classes appropriées - dans ce cas:
from Django.forms import TextInput, Textarea
from Django.db import models
Vous pouvez définir des attributs HTML arbitraires sur un widget à l'aide de sa propriété "attrs" .
Vous pouvez le faire dans l’administrateur Django en utilisant 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
ou avec une sous-classe de widget personnalisée et le dictionnaire 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}}
Une option rapide et simpliste consiste simplement à fournir un modèle personnalisé pour le modèle en question.
Si vous créez un modèle nommé admin/<app label>/<class name>/change_form.html
, l’administrateur utilisera ce modèle au lieu du modèle par défaut. Autrement dit, si vous avez un modèle nommé Person
dans une application nommée people
, vous créez un modèle nommé admin/people/person/change_form.html
.
Tous les modèles d’administrateur ont un bloc extrahead
que vous pouvez remplacer pour placer des éléments dans le <head>
, et la dernière pièce du puzzle est le fait que chaque champ a un identifiant HTML id_<field-name>
.
Donc, vous pouvez mettre quelque chose comme ceci dans votre modèle:
{% extends "admin/change_form.html" %}
{% block extrahead %}
{{ block.super }}
<style type="text/css">
#id_my_field { width: 100px; }
</style>
{% endblock %}
Pour changer la largeur d'un champ spécifique.
Fabriqué via 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
Si vous souhaitez modifier les attributs sur une instance par champ, vous pouvez ajouter la propriété "attrs" directement dans vos entrées de formulaire.
par exemple:
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 propriété "attrs" transmet essentiellement le balisage HTML qui ajustera le champ de formulaire. Chaque entrée est un tuple de l'attribut que vous souhaitez remplacer et de la valeur que vous souhaitez remplacer. Vous pouvez entrer autant d'attributs que vous le souhaitez, à condition de séparer chaque tuple par une virgule.
Le meilleur moyen que j'ai trouvé est quelque chose comme ça:
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
Il est bien meilleur pour ModelForm que de remplacer des champs avec différents widgets, car il conserve les attributs name
et help_text
ainsi que les valeurs par défaut des champs de modèle, vous évitant ainsi de les copier dans votre formulaire.
J'ai eu un problème similaire avec TextField. J'utilise Django 1.0.2 et je voulais changer la valeur par défaut pour "lignes" dans la zone de texte associée. formfield_overrides n'existe pas dans cette version. Remplacer formfield_for_dbfield fonctionnait, mais je devais le faire pour chacune de mes sous-classes ModelAdmin, sinon cela provoquerait une erreur de récursivité. Finalement, j'ai trouvé que l'ajout du code ci-dessous à models.py fonctionne:
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)
Puis utilisez MyTextField au lieu de TextField lors de la définition de vos modèles. Je l'ai adapté de cette réponse à une question similaire.
Vous pouvez toujours définir la taille de vos champs dans une feuille de style personnalisée et indiquer à Django de l'utiliser pour votre classe ModelAdmin:
class MyModelAdmin(ModelAdmin):
class Media:
css = {"all": ("my_stylesheet.css",)}
C'est bien décrit dans Django FAQ :
Q: Comment modifier les attributs d'un widget sur un champ de mon modèle?
A: Remplace le formulaire formfield_for_dbfield dans la classe 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)
pour 1.6, en utilisant des formulaires, je devais spécifier les attributs de la zone de texte à l'intérieur du champ:
test1 = forms.CharField(max_length=400, widget=forms.Textarea( attrs={'rows':'2', 'cols': '10'}), initial='', help_text=helptexts.helptxt['test'])
Même réponse que msdin mais avec TextInput au lieu 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)
Et encore un exemple:
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 vous souhaitez modifier uniquement une taille de champs spécifique, vous pouvez l'utiliser.
Si vous travaillez avec un champ ForeignKey impliquant des choix/options/un menu déroulant, vous pouvez remplacer formfield_for_foreignkey
dans l'instance 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)
Voici une solution simple mais flexible. Utilisez un formulaire personnalisé pour remplacer certains 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
Les widgets donnés dans ElephantForm
remplaceront ceux par défaut. La clé est la représentation sous forme de chaîne du champ. Les champs non spécifiés dans le formulaire utiliseront le widget par défaut.
Notez que bien que age
soit une IntegerField
, nous pouvons utiliser le widget TextInput
, car contrairement à NumberInput
, TextInput
accepte l'attribut size
.
Cette solution est décrite dans cet article .