Ubah ukuran bidang di Django Admin

108

Django cenderung mengisi ruang horizontal ketika menambah atau mengedit entri pada admin, tetapi, dalam beberapa kasus, adalah pemborosan ruang yang nyata, ketika, misalnya, mengedit bidang tanggal, lebar 8 karakter, atau bidang karakter, juga 6 atau 8 karakter lebar, dan kemudian kotak edit naik menjadi 15 atau 20 karakter.

Bagaimana cara memberi tahu admin seberapa lebar kotak teks seharusnya, atau tinggi kotak edit BidangTeks?

Andor
sumber
9
Jelas, Anda lupa melakukan itu dalam kasus ini. Lebih dari dua tahun kemudian. =)
casperOne
Proyek dibatalkan dan saya tidak melihat kode untuk sementara waktu. Saya mungkin memulai proyek baru bulan depan, jadi mungkin saya akan melihat ini lagi: D
Andor

Jawaban:

210

Anda harus menggunakan ModelAdmin.formfield_overrides .

Ini cukup mudah - dalam admin.py, tentukan:

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
sumber
1
Inilah yang saya cari tanpa harus membuat beberapa penyesuaian template yang konyol. Terima kasih!
Chris
2
Perhatikan bahwa ini tidak akan berfungsi jika filter_horizontalatau filter_verticaldisetel untuk bidang terkait di YourModelAdmin. Saya telah menghabiskan beberapa waktu untuk memikirkan hal ini.
Dennis Golomazov
Apakah ada kekurangan dalam bentuk ini? Saya tidak menemukan cara untuk mengatur atribut attrs untuk semua Textareas.
Julian
1
Saya hanya menggunakan models.TextField: {'widget': Textarea(attrs={'rows':4})}tetapi lebarnya menjadi lebih kecil juga.
Smit Johnth
Tampaknya sulit untuk memiliki ukuran yang sama.
Sören
45

Anda dapat menyetel atribut HTML sewenang-wenang pada widget menggunakan properti "attrs" -nya .

Anda dapat melakukan ini pada admin Django menggunakan 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

atau dengan subkelas Widget khusus dan kamus 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
sumber
30

Untuk mengubah lebar bidang tertentu.

Dibuat melalui 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
sumber
Menurut pendapat saya, ini adalah jawaban terbaik, karena memungkinkan untuk mengubah bidang individu tanpa harus membuat formulir baru.
rbennell
21

Pilihan cepat dan kotor adalah dengan menyediakan template kustom untuk model yang dimaksud.

Jika Anda membuat template dengan nama admin/<app label>/<class name>/change_form.htmlmaka admin akan menggunakan template tersebut sebagai pengganti default. Artinya, jika Anda memiliki model yang dinamai Persondalam aplikasi bernama people, Anda akan membuat template bernama admin/people/person/change_form.html.

Semua templat admin memiliki extraheadblok yang dapat Anda timpa untuk menempatkan barang di dalamnya <head>, dan bagian terakhir dari teka-teki tersebut adalah kenyataan bahwa setiap bidang memiliki ID HTML id_<field-name>.

Jadi, Anda bisa meletakkan sesuatu seperti berikut ini di template Anda:

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

{% block extrahead %}
  {{ block.super }}
  <style type="text/css">
    #id_my_field { width: 100px; }
  </style>
{% endblock %}
jacobian
sumber
Terima kasih! Ini dan jawaban oleh alanjds sangat membantu untuk mengubah tata letak di antarmuka admin pada basis per bidang, daripada basis per jenis bidang.
nealmcb
10

Jika Anda ingin mengubah atribut pada instance per-field, Anda dapat menambahkan properti "attrs" langsung ke entri formulir Anda.

sebagai contoh:

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

Properti "attrs" pada dasarnya meneruskan markup HTML yang akan menyesuaikan bidang formulir. Setiap entri adalah tupel dari atribut yang ingin Anda ganti dan nilai yang ingin Anda timpa. Anda dapat memasukkan atribut sebanyak yang Anda suka selama Anda memisahkan setiap tupel dengan koma.

Jonathan
sumber
IMO cara terbaik untuk memodifikasi hanya satu bidang dan tidak semua widget TextInput sekaligus (seperti jawaban yang diterima)
ascripter
7

Cara terbaik yang saya temukan adalah seperti ini:

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

Ini jauh lebih baik untuk ModelForm daripada menimpa bidang dengan widget berbeda, karena mempertahankan namedan help_textatribut serta nilai default bidang model, jadi Anda tidak perlu menyalinnya ke formulir Anda.

kurczak.dll
sumber
7

Saya memiliki masalah serupa dengan TextField. Saya menggunakan Django 1.0.2 dan ingin mengubah nilai default untuk 'baris' dalam area teks terkait. formfield_overrides tidak ada pada versi ini. Mengganti formfield_for_dbfield berfungsi tetapi saya harus melakukannya untuk setiap subkelas ModelAdmin saya atau itu akan menghasilkan kesalahan rekursi. Akhirnya, saya menemukan bahwa menambahkan kode di bawah ini ke models.py berfungsi:

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)

Kemudian gunakan MyTextField sebagai ganti TextField saat menentukan model Anda. Saya menyesuaikannya dari jawaban ini ke pertanyaan serupa.

msdin
sumber
5

Ini dijelaskan dengan baik di Django FAQ :

Q: Bagaimana cara mengubah atribut widget pada bidang dalam model saya?

A: Ganti formfield_for_dbfield di kelas 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
sumber
Saat saya menggunakan teknik ini, teks bantuan tidak akan muncul, dan jika itu TabularInline, tajuk kolom menjadi 'Tidak Ada'.
Steven T. Snyder
1
Ini bukan pendekatan yang baik, karena Anda menghapus semua pengaturan lain di CharField. Misalnya, secara default, ini akan dengan cerdas mendeteksi apakah bidang formulir harus diperlukan atau tidak, tetapi kode ini menghancurkannya. Sebagai gantinya, Anda harus menyetel widget pada nilai yang dikembalikan oleh panggilan super () Anda.
Cerin
5

Anda selalu dapat menyetel ukuran bidang Anda dalam lembar gaya kustom dan memberitahu Django untuk menggunakan itu untuk kelas ModelAdmin Anda:

class MyModelAdmin(ModelAdmin):
    class Media:
        css = {"all": ("my_stylesheet.css",)}
Gonzalo
sumber
jawaban Terbaik! tanpa mengutak-atik formulir dan atribut (dan kemungkinan efek samping), hanya file css, yang dapat - dengan id / kelas yang ada dalam formulir admin django - dengan mudah menargetkan hanya beberapa, atau bahkan semua bidang. besar!
benzkji
2

untuk 1.6, menggunakan formulir saya harus menentukan atribut textarea di dalam charfield:

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

Jawaban yang sama dengan msdin tetapi dengan TextInput, bukan 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
sumber
1

Berikut ini solusi sederhana, namun fleksibel. Gunakan formulir kustom untuk mengganti beberapa 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

Widget yang diberikan ElephantFormakan menggantikan widget default. Kuncinya adalah representasi string dari lapangan. Bidang yang tidak ditentukan dalam formulir akan menggunakan widget default.

Perhatikan bahwa meskipun ageadalah IntegerFieldkita dapat menggunakan TextInputwidget, karena tidak seperti NumberInput, TextInputmenerima sizeatribut.

Solusi ini dijelaskan di artikel ini .

Eerik Sven Puudist
sumber
0

Jika Anda bekerja dengan bidang ForeignKey yang melibatkan pilihan / opsi / menu tarik-turun, Anda dapat mengganti formfield_for_foreignkeydi contoh 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)

Informasi lebih lanjut tentang pola ini di sini dan di sini .

mih
sumber
-1

Dan satu contoh lagi juga:

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

Jika Anda hanya ingin mengedit ukuran bidang tertentu, Anda dapat menggunakan ini.

mevaka
sumber