web-dev-qa-db-fra.com

Redimensionner les champs dans Django Admin

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?

99
Andor

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
184
jki

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}}
42
Carl Meyer

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

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
21
alanjds

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.

10
Jonathan

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. 

7
kurczak

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.

7
msdin

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

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)
5
HardQuestions

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'])
2
deddu

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)
1
dan-klasson

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.

0
mevaka

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)

Plus d'informations sur ce modèle ici et ici .

0
Matt Ian Hong

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 .

0
Eerik Sven Puudist