Jak dodać symbol zastępczy na CharField w Django?

195

Weź na przykład ten bardzo prosty formularz:

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

Zostanie to zrenderowane w szablonie:

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

Chcę jednak dodać placeholderatrybut do tego pola o wartości Searchtak, aby HTML wyglądał mniej więcej tak:

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

Najlepiej chciałbym przekazać wartość symbolu zastępczego do CharFieldklasy formularza przez słownik lub coś w stylu:

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

Jaki byłby najlepszy sposób na osiągnięcie tego?

Joelbitar
źródło

Odpowiedzi:

281

Przejrzyj dokumentację widżetów . Zasadniczo wyglądałoby to tak:

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

Więcej pisania, tak, ale separacja pozwala na lepszą abstrakcję bardziej skomplikowanych przypadków.

Możesz także zadeklarować widgetsatrybut zawierający <field name> => <widget instance>mapowanie bezpośrednio w Metaswojej ModelFormpodklasie.

Mike Axiak
źródło
musisz określić forms.TextInputzrobić attrs={'placeholder': 'Search'}deklarację?
JhovaniC
1
@OvedD, wiem, że to jest stare, ale zobacz to pytanie: stackoverflow.com/questions/4341739/…
NotSimon
1
@OvedD: zobacz moją odpowiedź, jak to zrobić za pomocą ModelForm
Hamish Downer
1
To głupie, że musisz określić widżet, aby dodać symbol zastępczy. Powinieneś być w stanie edytować atrybuty widżetu bez
przesłonięcia
W przypadku
języka
60

W przypadku ModelForm możesz użyć klasy Meta w następujący sposób:

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
źródło
Zauważ, że w takim przypadku nie możesz podać pola w treści klasy.
Czy S
To była dla mnie najłatwiejsza metoda - i miło było, że wszystkie pozostałe atrybuty (tj. Wymagane) były nadal automatycznie dodawane bez konieczności ich podawania.
JxAxMxIxN
41

Wszystkie pozostałe metody są dobre. Jeśli jednak nie chcesz określać pola (np. W przypadku niektórych metod dynamicznych), możesz użyć tego:

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

Pozwala także na to, by symbol zastępczy zależał od instancji dla ModelForms z określoną instancją.

znak
źródło
7
Jest to świetne, ponieważ pozwala uniknąć powielania długich instancji widżetów dla bardziej skomplikowanych obiektów, takich jak ModelMultipleChoiceField. Dzięki!
donturner
1
Podobny duch: for f in MyCommentForm.base_fields.values(): f.widget.attrs["placeholder"] = f.labelale bardziej podoba mi się twoja metoda konstruktora.
jozxyqk
21

Możesz użyć tego kodu, aby dodać symbol zastępczy attr dla każdego pola TextInput w formularzu. Tekst zastępczy zostanie pobrany z etykiet pola modelowego.

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
Jewgienij Szchemelew
źródło
19

Świetne pytanie. Istnieją trzy rozwiązania, o których wiem:

Rozwiązanie nr 1

Zamień domyślny widget.

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

Rozwiązanie nr 2

Dostosuj domyślny widget. Jeśli używasz tego samego widżetu, którego zwykle używa pole, możesz go po prostu dostosować zamiast tworzyć zupełnie nowy.

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

Rozwiązanie nr 3

Wreszcie, jeśli pracujesz z formularzem modelu, to ( oprócz dwóch poprzednich rozwiązań ) masz opcję określenia niestandardowego widgetu dla pola poprzez ustawienie widgetsatrybutu Metaklasy wewnętrznej .

class CommentForm(forms.ModelForm):  
    class Meta:
        model = Comment
        widgets = {
            'body': forms.Textarea(attrs={'cols': 80, 'rows': 20})
        }
Dwayne Crooks
źródło
1
Właśnie miałem napisać rozwiązanie jak twoje # 2. Chciałbym dodać, że można zastosować operacje na wszystkich polach, wykonując iterację self.fields, np .:for field_name in self.fields: self.fields[field_name].widget.attrs.update({"placeholder": sth})
Alberto Chiusole
@AlbertoChiusole Tak, możesz, jeśli to właśnie chcesz zrobić. Dzięki za zwrócenie na to uwagi.
Dwayne Crooks,
@DwayneCrooks Proponuję zaktualizować swój numer 3 zgodnie z rozwiązaniem cdosborn , ponieważ jest on o wiele krótszy i bardziej czytelny.
Marian,
1

Nie jest pożądane, aby wiedzieć, jak utworzyć instancję widgetu, gdy chcesz po prostu zastąpić jego symbol zastępczy.

    q = forms.CharField(label='search')
    ...
    q.widget.attrs['placeholder'] = "Search"
cdosborn
źródło
0

Przez większość czasu po prostu chcę, aby wszystkie symbole zastępcze były równe pełnej nazwie pola zdefiniowanej w moich modelach

Dodałem mixin, aby łatwo to zrobić w dowolnej formie, którą utworzę,

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

I

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
źródło
-2

Po przyjrzeniu się twojej metodzie użyłem tej metody do jej rozwiązania.

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
źródło
2
Pamiętaj, że zawartość przepełnienia stosu musi być w języku angielskim. Poza tym wydaje się, że jest to post „ja też”, a nie odpowiedź na postawione powyżej pytanie.
TylerH
Powiedziałbym, że posty „ja też” są w porządku, jeśli dodają więcej szczegółów. Co z tym podejściem różni się od pozostałych? Jaka jest tutaj technika lub podstawowa nauka?
halfer