Ridimensiona i campi in Django Admin


107

Django tende a riempire lo spazio orizzontale quando si aggiungono o si modificano voci sull'amministratore, ma, in alcuni casi, è un vero spreco di spazio, quando, ad esempio, si modifica un campo data, largo 8 caratteri, o un CharField, anche 6 o 8 caratteri di larghezza, quindi la casella di modifica arriva fino a 15 o 20 caratteri.

Come posso dire all'amministratore quanto dovrebbe essere larga una casella di testo o l'altezza di una casella di modifica TextField?


9
Ovviamente, ti sei dimenticato di farlo in questo caso. Più di due anni dopo. =)
— casper Il

Il progetto è stato abbandonato e per un po 'non ho potuto vedere il codice. Potrei iniziare un nuovo progetto il mese prossimo, quindi forse lo rivedrò: D
— Andor

Risposte:


209

Dovresti usare ModelAdmin.formfield_overrides .

È abbastanza facile - in admin.py, definire:

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
Questo era esattamente quello che stavo cercando senza dover apportare alcune ridicole personalizzazioni dei modelli. Grazie!
— Chris,

2
Tieni presente che questo non funzionerà se filter_horizontalo filter_verticalè impostato per i campi corrispondenti in YourModelAdmin. Ho passato un po 'di tempo a capirlo.
— Dennis Golomazov

C'è qualcosa di strano in una forma? Non ho trovato un modo per impostare l'attributo attrs per tutte le aree di testo.
— Julian,

1
Ho usato solo models.TextField: {'widget': Textarea(attrs={'rows':4})}ma anche la larghezza è diventata più piccola.
— Smit Johnth

Apparentemente è difficile averli delle stesse dimensioni.
— Sören

44

È possibile impostare attributi HTML arbitrari su un widget utilizzando la sua proprietà "attrs" .

Puoi farlo nell'amministratore di Django usando 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

o con una sottoclasse Widget personalizzata e il dizionario 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}}

29

Per modificare la larghezza per un campo specifico.

Realizzato tramite 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

Secondo me questa è la risposta migliore, poiché consente di modificare i singoli campi senza dover creare un nuovo modulo.
— rbennell

20

Un'opzione rapida e sporca è semplicemente fornire un modello personalizzato per il modello in questione.

Se crei un modello denominato, admin/<app label>/<class name>/change_form.htmll'amministratore utilizzerà quel modello anziché quello predefinito. Cioè, se hai un modello denominato Personin un'app denominata people, creerai un modello denominato admin/people/person/change_form.html.

Tutti i modelli di amministrazione hanno un extraheadblocco che puoi sovrascrivere per inserire elementi in <head>, e l'ultimo pezzo del puzzle è il fatto che ogni campo ha un ID HTML di id_<field-name>.

Quindi, potresti inserire qualcosa di simile nel tuo modello:

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

{% block extrahead %}
  {{ block.super }}
  <style type="text/css">
    #id_my_field { width: 100px; }
  </style>
{% endblock %}

Grazie! Questa e la risposta di alanjds sono molto utili per modificare il layout nell'interfaccia di amministrazione in base al campo, piuttosto che in base al tipo di campo.
— nealmcb

10

Se desideri modificare gli attributi su un'istanza per campo, puoi aggiungere la proprietà "attrs" direttamente alle voci del modulo.

per esempio:

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 proprietà "attrs" fondamentalmente passa lungo il markup HTML che regolerà il campo del modulo. Ogni voce è una tupla dell'attributo che si desidera sovrascrivere e il valore con cui si desidera sovrascriverlo. Puoi inserire tutti gli attributi che desideri purché separa ogni tupla con una virgola.


IMO il modo migliore per modificare solo un singolo campo e non tutti i widget TextInput contemporaneamente (come fa la risposta accettata)
— ascritto

7

Il modo migliore che ho trovato è qualcosa del genere:

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

È molto meglio per ModelForm che sovrascrivere i campi con widget diversi, poiché conserva namee help_textattributi e anche i valori predefiniti dei campi del modello, quindi non è necessario copiarli nel modulo.


7

Ho avuto un problema simile con TextField. Sto usando Django 1.0.2 e volevo cambiare il valore predefinito per "righe" nella textarea associata. formfield_overrides non esiste in questa versione. L'override di formfield_for_dbfield ha funzionato, ma ho dovuto farlo per ciascuna delle mie sottoclassi ModelAdmin o avrebbe generato un errore di ricorsione. Alla fine, ho scoperto che l'aggiunta del codice seguente a models.py funziona:

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)

Quindi usa MyTextField invece di TextField quando definisci i tuoi modelli. L'ho adattato da questa risposta a una domanda simile.


5

È ben descritto nelle FAQ di Django :

D: Come si modificano gli attributi di un widget su un campo nel mio modello?

R: Sostituisci formfield_for_dbfield nella 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)

Quando utilizzo questa tecnica, il testo della guida non viene visualizzato e, se è un TabularInline, l'intestazione della colonna diventa "Nessuno".
— Steven T.Snyder

1
Questo non è un buon approccio, poiché stai cancellando tutte le altre impostazioni in CharField. Ad esempio, per impostazione predefinita, rileverà in modo intelligente se il campo del modulo deve essere richiesto o meno, ma questo codice lo distrugge. Dovresti invece impostare il widget sul valore restituito dalla tua chiamata super ().
— Cerin

5

Puoi sempre impostare le dimensioni dei tuoi campi in un foglio di stile personalizzato e dire a Django di usarlo per la tua classe ModelAdmin:

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

migliore risposta! non giocherellare con campi e attributi (e possibili effetti collaterali), solo un file css, che può - con gli id ​​/ classi esistenti nei moduli di amministrazione di django - indirizzare facilmente solo alcuni o anche tutti i campi. grande!
— benzkji

2

per 1.6, usando i form ho dovuto specificare gli attributi della textarea all'interno del charfield:

test1 = forms.CharField(max_length=400, widget=forms.Textarea( attrs={'rows':'2', 'cols': '10'}),  initial='', help_text=helptexts.helptxt['test'])

1

Stessa risposta di msdin ma con TextInput invece di 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

Ecco una soluzione semplice ma flessibile. Usa un modulo personalizzato per sovrascrivere alcuni widget.

# 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

I widget forniti ElephantFormsostituiranno quelli predefiniti. La chiave è la rappresentazione di stringa del campo. I campi non specificati nel modulo utilizzeranno il widget predefinito.

Nota che sebbene agesia un IntegerFieldpossiamo usare il TextInputwidget, perché a differenza di NumberInput, TextInputaccetta l' sizeattributo.

Questa soluzione è descritta in questo articolo .


0

Se stai lavorando con un campo ForeignKey che coinvolge scelte / opzioni / un menu a discesa, puoi eseguire l'override formfield_for_foreignkeynell'istanza di amministrazione:

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)

Maggiori informazioni su questo modello qui e qui .


-1

E anche un altro esempio:

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

Se vuoi modificare solo una dimensione specifica dei campi, puoi usarla.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.