Bagaimana cara menambahkan placeholder di CharField di Django?

195

Ambil formulir yang sangat sederhana ini misalnya:

class SearchForm(Form):
    q = forms.CharField(label='search')

Ini akan diberikan dalam templat:

<input type="text" name="q" id="id_q" />

Namun, saya ingin menambahkan placeholderatribut ke bidang ini dengan nilai Searchsehingga HTML akan terlihat seperti:

<input type="text" name="q" id="id_q" placeholder="Search" />

Lebih disukai saya ingin meneruskan nilai placeholder ke CharFielddalam kelas bentuk melalui kamus atau sesuatu seperti:

q = forms.CharField(label='search', placeholder='Search')

Apa cara terbaik untuk mencapai ini?

Joelbitar
sumber

Jawaban:

281

Lihatlah dokumentasi widget . Pada dasarnya akan terlihat seperti:

q = forms.CharField(label='search', 
                    widget=forms.TextInput(attrs={'placeholder': 'Search'}))

Lebih banyak menulis, ya, tetapi pemisahan memungkinkan abstraksi yang lebih baik dari kasus yang lebih rumit.

Anda juga dapat mendeklarasikan widgetsatribut yang berisi <field name> => <widget instance>pemetaan langsung pada Metaanda ModelFormsub-kelas.

Mike Axiak
sumber
apakah Anda perlu menentukan forms.TextInputuntuk melakukan attrs={'placeholder': 'Search'}deklarasi?
JhovaniC
1
@OvedD, saya tahu ini sudah tua, tetapi lihat pertanyaan ini: stackoverflow.com/questions/4341739/…
NotSimon
1
@OvedD: lihat jawaban saya untuk bagaimana melakukan ini dengan ModelForm
Hamish Downer
1
Sangat bodoh bahwa Anda harus menentukan widget untuk menambahkan placeholder. Anda harus dapat mengedit atribut widget tanpa mengesampingkan seluruh widget ...
dspacejs
Untuk bahasa Cina, Anda memerlukan Anda sebelumnya seperti ini: {'placeholder': u '搜索'}
shellbye
60

Untuk ModelForm, Anda bisa menggunakan kelas Meta sebagai berikut:

from django import forms

from .models import MyModel

class MyModelForm(forms.ModelForm):
    class Meta:
        model = MyModel
        widgets = {
            'name': forms.TextInput(attrs={'placeholder': 'Name'}),
            'description': forms.Textarea(
                attrs={'placeholder': 'Enter description here'}),
        }
Hamish Downer
sumber
Perhatikan bahwa dalam hal ini Anda tidak bisa menentukan bidang dalam tubuh kelas.
Will S
Ini adalah metode termudah bagi saya - dan itu menyenangkan bahwa semua atribut lainnya (yaitu diperlukan) masih ditambahkan secara otomatis tanpa saya harus menentukannya.
JxAxMxIxN
41

Metode lainnya semuanya baik. Namun, jika Anda memilih untuk tidak menentukan bidang (mis. Untuk beberapa metode dinamis), Anda dapat menggunakan ini:

def __init__(self, *args, **kwargs):
    super(MyForm, self).__init__(*args, **kwargs)
    self.fields['email'].widget.attrs['placeholder'] = self.fields['email'].label or '[email protected]'

Ini juga memungkinkan placeholder bergantung pada instance untuk ModelForms dengan instance yang ditentukan.

Menandai
sumber
7
Ini bagus karena menghindari duplikat instantiasi widget yang panjang untuk objek yang lebih rumit seperti ModelMultipleChoiceField. Terima kasih!
donturner
1
Semangat serupa:, for f in MyCommentForm.base_fields.values(): f.widget.attrs["placeholder"] = f.labeltapi saya lebih suka metode konstruktor Anda.
jozxyqk
21

Anda bisa menggunakan kode ini untuk menambahkan tempat penampung attr untuk setiap bidang TextInput di formulir Anda. Teks untuk penampung akan diambil dari label bidang model.

class PlaceholderDemoForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(PlaceholderDemoForm, self).__init__(*args, **kwargs)
        for field_name in self.fields:
            field = self.fields.get(field_name)  
            if field:
                if type(field.widget) in (forms.TextInput, forms.DateInput):
                    field.widget = forms.TextInput(attrs={'placeholder': field.label})

    class Meta:
        model = DemoModel
Yevgeniy Shchemelev
sumber
19

Pertanyaan yang bagus Ada tiga solusi yang saya ketahui:

Solusi # 1

Ganti widget default.

class SearchForm(forms.Form):  
    q = forms.CharField(
            label='Search',
            widget=forms.TextInput(attrs={'placeholder': 'Search'})
        )

Solusi # 2

Kustomisasi widget default. Jika Anda menggunakan widget yang sama dengan yang biasa digunakan bidang tersebut, maka Anda bisa menyesuaikannya alih-alih membuat instance yang sama sekali baru.

class SearchForm(forms.Form):  
    q = forms.CharField(label='Search')

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['q'].widget.attrs.update({'placeholder': 'Search'})

Solusi # 3

Terakhir, jika Anda bekerja dengan formulir model maka ( selain dua solusi sebelumnya ) Anda memiliki opsi untuk menentukan widget khusus untuk bidang dengan mengatur widgetsatribut Metakelas dalam .

class CommentForm(forms.ModelForm):  
    class Meta:
        model = Comment
        widgets = {
            'body': forms.Textarea(attrs={'cols': 80, 'rows': 20})
        }
Dwayne Crooks
sumber
1
Saya akan menulis solusi sebagai milik Anda # 2. Saya ingin menambahkan bahwa Anda dapat menerapkan operasi di semua bidang dengan mengulangi self.fields, misalnya:for field_name in self.fields: self.fields[field_name].widget.attrs.update({"placeholder": sth})
Alberto Chiusole
@AlbertoChiusole Ya Anda bisa, jika itu yang ingin Anda lakukan. Terima kasih telah menunjukkannya.
Dwayne Crooks
@DwayneCrooks Saya sarankan Anda memperbarui # 3 sesuai solusi cdosborn , karena cara ini lebih pendek dan lebih mudah dibaca.
Marian
1

Tidak diinginkan harus tahu cara membuat instance widget saat Anda hanya ingin mengganti placeholder-nya.

    q = forms.CharField(label='search')
    ...
    q.widget.attrs['placeholder'] = "Search"
cdosborn
sumber
0

Sebagian besar waktu saya hanya ingin semua placeholder sama dengan nama verbose bidang yang ditentukan dalam model saya

Saya telah menambahkan mixin untuk dengan mudah melakukan ini ke bentuk apa pun yang saya buat,

class ProductForm(PlaceholderMixin, ModelForm):
    class Meta:
        model = Product
        fields = ('name', 'description', 'location', 'store')

Dan

class PlaceholderMixin:
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs):
        field_names = [field_name for field_name, _ in self.fields.items()]
        for field_name in field_names:
            field = self.fields.get(field_name)
            field.widget.attrs.update({'placeholder': field.label})
Viktor Johansson
sumber
-2

Setelah melihat metode Anda, saya menggunakan metode ini untuk menyelesaikannya.

class Register(forms.Form):
    username = forms.CharField(label='用户名', max_length=32)
    email = forms.EmailField(label='邮箱', max_length=64)
    password = forms.CharField(label="密码", min_length=6, max_length=16)
    captcha = forms.CharField(label="验证码", max_length=4)

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    for field_name in self.fields:
        field = self.fields.get(field_name)
        self.fields[field_name].widget.attrs.update({
            "placeholder": field.label,
            'class': "input-control"
        })
lber l
sumber
2
Harap dicatat bahwa konten harus dalam bahasa Inggris di Stack Overflow. Selain itu, ini tampaknya menjadi posting "saya juga", bukan jawaban atas pertanyaan yang diajukan di atas.
TylerH
Saya akan mengatakan bahwa posting "saya juga" tidak apa-apa jika mereka menambahkan lebih detail. Bagaimana dengan pendekatan ini berbeda dengan yang lain? Apa teknik atau pembelajaran penting di sini?
Halfer