Ändern Sie die Größe von Feldern in Django Admin

107

Django füllt normalerweise horizontalen Raum aus, wenn Einträge im Administrator hinzugefügt oder bearbeitet werden. In einigen Fällen ist dies jedoch eine echte Platzverschwendung, wenn ein Datumsfeld mit einer Breite von 8 Zeichen oder ein CharField mit 6 oder 8 Zeichen bearbeitet wird Zeichen breit, und dann geht das Bearbeitungsfeld auf 15 oder 20 Zeichen.

Wie kann ich dem Administrator mitteilen, wie breit ein Textfeld sein soll oder wie hoch ein TextField-Bearbeitungsfeld ist?

Andor
quelle
9
Offensichtlich haben Sie das in diesem Fall vergessen. Mehr als zwei Jahre später. =)
casperOne
Das Projekt wurde eingestellt und ich konnte eine Weile keinen Code sehen. Ich kann nächsten Monat ein neues Projekt beginnen, also sehe ich das vielleicht noch einmal: D
Andor

Antworten:

209

Sie sollten ModelAdmin.formfield_overrides verwenden .

Es ist ganz einfach - admin.pydefinieren Sie:

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)
jki
quelle
1
Dies war genau das, wonach ich gesucht habe, ohne lächerliche Vorlagenanpassungen vornehmen zu müssen. Vielen Dank!
Chris
2
Beachten Sie, dass dies nicht funktioniert, wenn filter_horizontaloder filter_verticalfür die entsprechenden Felder in YourModelAdmin festgelegt ist. Ich habe einige Zeit damit verbracht, dies herauszufinden.
Dennis Golomazov
Gibt es irgendwelche Probleme in einer Form? Ich habe keine Möglichkeit gefunden, das Attribut attrs für alle Textbereiche festzulegen.
Julian
1
Ich habe nur verwendet, models.TextField: {'widget': Textarea(attrs={'rows':4})}aber die Breite wurde auch kleiner.
Smit Johnth
Es ist schwer, sie anscheinend gleich groß zu haben.
Sören
44

Sie können beliebige HTML-Attribute für ein Widget mithilfe der Eigenschaft "attrs" festlegen .

Sie können dies im Django-Administrator mit formfield_for_dbfield tun:

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

oder mit einer benutzerdefinierten Widget-Unterklasse und dem Wörterbuch 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}}
Carl Meyer
quelle
29

So ändern Sie die Breite für ein bestimmtes Feld.

Erstellt über 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
Alanjds
quelle
Meiner Meinung nach ist dies die beste Antwort, da einzelne Felder geändert werden können, ohne dass ein neues Formular erstellt werden muss.
Rbennell
20

Eine schnelle und schmutzige Option besteht darin, einfach eine benutzerdefinierte Vorlage für das betreffende Modell bereitzustellen.

Wenn Sie eine Vorlage mit dem Namen erstellen, verwendet admin/<app label>/<class name>/change_form.htmlder Administrator diese Vorlage anstelle der Standardvorlage. Wenn Sie also ein Modell Personin einer App mit dem Namen haben people, erstellen Sie eine Vorlage mit dem Namen admin/people/person/change_form.html.

Alle Admin-Vorlagen haben einen extraheadBlock, den Sie überschreiben können, um Inhalte in das <head>Feld einzufügen id_<field-name>. Das letzte Puzzleteil ist die Tatsache, dass jedes Feld eine HTML-ID von hat .

Sie können also Folgendes in Ihre Vorlage einfügen:

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

{% block extrahead %}
  {{ block.super }}
  <style type="text/css">
    #id_my_field { width: 100px; }
  </style>
{% endblock %}
jacobian
quelle
Vielen Dank! Dies und die Antwort von alanjds sind sehr hilfreich, um das Layout in der Administrationsoberfläche auf Feldbasis und nicht auf Feldbasis zu ändern.
Nealmcb
10

Wenn Sie die Attribute für eine Instanz pro Feld ändern möchten, können Sie die Eigenschaft "attrs" direkt zu Ihren Formulareinträgen hinzufügen.

beispielsweise:

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')

Die Eigenschaft "attrs" übergibt im Wesentlichen das HTML-Markup, mit dem das Formularfeld angepasst wird. Jeder Eintrag ist ein Tupel des Attributs, das Sie überschreiben möchten, und des Werts, mit dem Sie es überschreiben möchten. Sie können so viele Attribute eingeben, wie Sie möchten, solange Sie jedes Tupel durch ein Komma trennen.

Jonathan
quelle
IMO der beste Weg, um nur ein einziges Feld und nicht alle TextInput-Widgets gleichzeitig zu ändern (wie es die akzeptierte Antwort tut)
Ascripter
7

Der beste Weg, den ich gefunden habe, ist ungefähr so:

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

Es ist viel besser für Modelform als zwingende Felder mit verschiedenen Widgets, wie es bewahrt nameund help_textAttribute und auch die Standardwerte der Modellfelder, so dass Sie nicht in Ihrer Form haben zu kopieren.

kurczak
quelle
7

Ich hatte ein ähnliches Problem mit TextField. Ich verwende Django 1.0.2 und wollte den Standardwert für 'Zeilen' im zugehörigen Textbereich ändern. formfield_overrides existiert in dieser Version nicht. Das Überschreiben von formfield_for_dbfield hat funktioniert, aber ich musste es für jede meiner ModelAdmin-Unterklassen tun, da dies sonst zu einem Rekursionsfehler führen würde. Schließlich stellte ich fest, dass das Hinzufügen des folgenden Codes zu models.py funktioniert:

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)

Verwenden Sie dann MyTextField anstelle von TextField, wenn Sie Ihre Modelle definieren. Ich habe es von angepasst dieser Antwort auf eine ähnliche Frage .

msdin
quelle
5

Es ist gut in Django FAQ beschrieben :

F: Wie ändere ich die Attribute für ein Widget in einem Feld in meinem Modell?

A: Überschreiben Sie das Feld formfield_for_db in der Klasse 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)
HardQuestions
quelle
Wenn ich diese Technik verwende, wird der Hilfetext nicht angezeigt. Wenn es sich um eine TabularInline handelt, wird die Spaltenüberschrift zu "Keine".
Steven T. Snyder
1
Dies ist kein guter Ansatz, da Sie alle anderen Einstellungen im CharField löschen. Standardmäßig wird beispielsweise intelligent erkannt, ob das Formularfeld erforderlich sein sollte oder nicht, aber dieser Code zerstört dies. Sie sollten stattdessen das Widget auf den Wert setzen, der von Ihrem super () -Aufruf zurückgegeben wird.
Cerin
5

Sie können Ihre Feldgrößen jederzeit in einem benutzerdefinierten Stylesheet festlegen und Django anweisen, diese für Ihre ModelAdmin-Klasse zu verwenden:

class MyModelAdmin(ModelAdmin):
    class Media:
        css = {"all": ("my_stylesheet.css",)}
Gonzalo
quelle
beste Antwort! Kein Fummeln mit Formularfeldern und Attributen (und möglichen Nebenwirkungen), nur eine CSS-Datei, die - mit vorhandenen IDs / Klassen in Django-Administrationsformularen - problemlos nur auf einige oder sogar alle Felder abzielen kann. groß auf!
Benzkji
2

Für 1.6 musste ich mithilfe von Formularen die Attribute des Textbereichs im Zeichenfeld angeben:

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

Gleiche Antwort wie msdin, jedoch mit TextInput anstelle von 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)
dan-klasson
quelle
1

Hier ist eine einfache und dennoch flexible Lösung. Verwenden Sie ein benutzerdefiniertes Formular, um einige Widgets zu überschreiben.

# 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

Die in angegebenen Widgets ElephantFormersetzen die Standard- Widgets . Der Schlüssel ist die Zeichenfolgendarstellung des Feldes. Felder, die nicht im Formular angegeben sind, verwenden das Standard-Widget.

Beachten Sie, dass , obwohl ageeine ist IntegerFieldkönnen wir die VerwendungTextInput , widget, denn im Gegensatz zu der NumberInput, TextInputdie akzeptiert sizeAttribut.

Diese Lösung wird in diesem Artikel beschrieben .

Eerik Sven Puudist
quelle
0

Wenn Sie mit einem ForeignKey-Feld arbeiten, das Auswahlmöglichkeiten / Optionen / ein Dropdown-Menü enthält, können Sie formfield_for_foreignkeyin der Admin-Instanz Folgendes überschreiben :

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)

Weitere Informationen zu diesem Muster hier und hier .

mih
quelle
-1

Und noch ein Beispiel:

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

Wenn Sie nur eine bestimmte Feldgröße bearbeiten möchten, können Sie diese verwenden.

Mevaka
quelle