Zmień rozmiar pól w Django Admin


109

Django ma tendencję do zapełniania poziomej przestrzeni podczas dodawania lub edytowania wpisów w panelu administracyjnym, ale w niektórych przypadkach jest to prawdziwa strata miejsca, gdy np. Edytowanie pola daty o szerokości 8 znaków lub CharField również 6 lub 8 znaków szerokich, a następnie pole edycji rozszerza się do 15 lub 20 znaków.

Jak mogę powiedzieć administratorowi, jak szerokie powinno być pole tekstowe lub jak wysokość pola edycji TextField?


9
Oczywiście zapomniałeś o tym zrobić w tym przypadku. Ponad dwa lata później. =)
casperOne

Projekt został porzucony i przez chwilę nie widziałem kodu. Mogę rozpocząć nowy projekt w przyszłym miesiącu, więc może jeszcze raz to zobaczę: D
Andor

Odpowiedzi:


211

Powinieneś użyć ModelAdmin.formfield_overrides .

To całkiem proste - admin.pyzdefiniuj:

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
To było dokładnie to, czego szukałem, bez konieczności dokonywania śmiesznych dostosowań szablonów. Dzięki!
Chris,

2
Zauważ, że to nie zadziała, jeśli filter_horizontallub filter_verticaljest ustawione dla odpowiednich pól w YourModelAdmin. Spędziłem trochę czasu, żeby to rozgryźć.
Dennis Golomazov

Czy jest coś dziwnego w formie? Nie znalazłem sposobu na ustawienie atrybutu attrs dla wszystkich Textareas.
Julian,

1
Użyłem tylko, models.TextField: {'widget': Textarea(attrs={'rows':4})}ale szerokość też się zmniejszyła.
Smit Johnth

Wydaje się, że trudno mieć je tej samej wielkości.
Sören

45

Możesz ustawić dowolne atrybuty HTML widżetu za pomocą jego właściwości „attrs” .

Możesz to zrobić w panelu administracyjnym Django za pomocą 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

lub z niestandardową podklasą Widget i słownikiem 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}}

30

Aby zmienić szerokość określonego pola.

Wykonane przez 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

Moim zdaniem to najlepsza odpowiedź, ponieważ pozwala na zmianę poszczególnych pól bez konieczności tworzenia nowego formularza.
rbennell,

21

Szybką i nieprzyjemną opcją jest po prostu zapewnienie niestandardowego szablonu dla danego modelu.

Jeśli utworzysz szablon o nazwie, admin/<app label>/<class name>/change_form.htmladministrator użyje tego szablonu zamiast domyślnego. Oznacza to, że jeśli masz model o nazwie Personw aplikacji o nazwie people, możesz utworzyć szablon o nazwie admin/people/person/change_form.html.

Wszystkie szablony administracyjne mają extraheadblok, który możesz nadpisać, aby umieścić rzeczy w <head>, a ostatnim elementem układanki jest fakt, że każde pole ma identyfikator HTML id_<field-name>.

Możesz więc umieścić w swoim szablonie coś takiego:

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

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

Dzięki! To i odpowiedź alanjds są bardzo pomocne przy zmianie układu w interfejsie administratora na podstawie poszczególnych pól, a nie poszczególnych typów pól.
nealmcb

10

Jeśli chcesz zmienić atrybuty instancji dla poszczególnych pól, możesz dodać właściwość „attrs” bezpośrednio do wpisów formularza.

na przykład:

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

Właściwość „attrs” zasadniczo przekazuje kod HTML, który dostosuje pole formularza. Każdy wpis jest krotką atrybutu, który chcesz przesłonić, oraz wartością, którą chcesz zastąpić. Możesz wprowadzić dowolną liczbę atrybutów, pod warunkiem, że oddzielisz każdą krotkę przecinkiem.


IMO to najlepszy sposób na modyfikację tylko jednego pola, a nie wszystkich widżetów TextInput naraz (tak jak robi to zaakceptowana odpowiedź)
ascripter

7

Najlepszy sposób, jaki znalazłem, to coś takiego:

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

Jest o wiele lepiej niż na ModelForm przesłanianie pól z różnych widgetów, jak zachowuje namei help_textatrybuty, a także domyślne wartości pól modelu, więc nie trzeba je skopiować do formularza.


7

Miałem podobny problem z TextField. Używam Django 1.0.2 i chciałem zmienić domyślną wartość dla „wierszy” w powiązanym obszarze tekstowym. formfield_overrides nie istnieje w tej wersji. Zastępowanie formfield_for_dbfield działało, ale musiałem to zrobić dla każdej z moich podklas ModelAdmin lub spowodowałoby to błąd rekursji. Ostatecznie stwierdziłem, że dodanie poniższego kodu do models.py działa:

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)

Następnie podczas definiowania modeli użyj MyTextField zamiast TextField. Zaadaptowałem to na podstawie tej odpowiedzi do podobnego pytania.


5

Jest to dobrze opisane w Django FAQ :

P: Jak zmienić atrybuty widgetu w polu w moim modelu?

Odp .: Zastąp formfield_for_dbfield w klasie 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)

Kiedy używam tej techniki, tekst pomocy nie pojawia się, a jeśli jest to TabularInline, nagłówek kolumny zmienia się na „Brak”.
Steven T. Snyder

1
To nie jest dobre podejście, ponieważ usuwasz wszystkie inne ustawienia w CharField. Na przykład domyślnie inteligentnie wykryje, czy pole formularza powinno być wymagane, ale ten kod to niszczy. Zamiast tego powinieneś ustawić widget na wartość zwracaną przez wywołanie super ().
Cerin

5

Zawsze możesz ustawić rozmiary pól w niestandardowym arkuszu stylów i powiedzieć Django, aby użył tego dla Twojej klasy ModelAdmin:

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

najlepsza odpowiedź! bez majstrowania przy polach formularzy i atrybutach (i możliwych efektach ubocznych), po prostu plik css, który może - z istniejącymi identyfikatorami / klasami w formularzach administracyjnych django - łatwo kierować tylko niektóre lub nawet wszystkie pola. wielki!
benzkji

2

dla wersji 1.6, używając formularzy musiałem określić atrybuty obszaru tekstowego wewnątrz pola charfield:

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

1

Taka sama odpowiedź jak msdin, ale z TextInput zamiast 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

Oto proste, ale elastyczne rozwiązanie. Użyj niestandardowego formularza, aby zastąpić niektóre widżety.

# 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

Widgety podane w ElephantForm zastąpią domyślne. Klucz to ciąg znaków reprezentujący pole. Pola niewyszczególnione w formularzu będą używały domyślnego widżetu.

Zauważ, że chociaż agejest to widżet, IntegerFieldmożemy użyć TextInputwidżetu, ponieważ w przeciwieństwie do NumberInput, TextInputakceptuje sizeatrybut.

To rozwiązanie jest opisane w tym artykule .


0

Jeśli pracujesz z polem ForeignKey, które obejmuje opcje / opcje / menu rozwijane, możesz nadpisać formfield_for_foreignkeyw instancji administratora:

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)

Więcej informacji na temat tego wzoru tutaj i tutaj .


-1

I jeszcze jeden przykład:

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

Jeśli chcesz edytować tylko określony rozmiar pól, możesz tego użyć.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.