Wie füge ich einen Platzhalter auf einem CharField in Django hinzu?

195

Nehmen Sie zum Beispiel diese sehr einfache Form:

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

Dies wird in der Vorlage gerendert:

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

Ich möchte placeholderdiesem Feld jedoch das Attribut mit dem Wert hinzufügen Search, damit der HTML-Code ungefähr so ​​aussieht:

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

Am besten möchte ich den Platzhalterwert CharFieldin der Formularklasse über ein Wörterbuch oder so etwas weitergeben:

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

Was wäre der beste Weg, um dies zu erreichen?

Joelbitar
quelle

Antworten:

281

Schauen Sie sich die Widgets-Dokumentation an . Grundsätzlich würde es so aussehen:

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

Mehr Schreiben, ja, aber die Trennung ermöglicht eine bessere Abstraktion komplizierterer Fälle.

Sie können auch ein deklarieren widgetsAttribut , das eine <field name> => <widget instance>Abbildung direkt auf die MetaIhre ModelFormUnterklasse.

Mike Axiak
quelle
Müssen Sie angeben forms.TextInput, um die attrs={'placeholder': 'Search'}Deklaration durchzuführen?
JhovaniC
1
@OvedD, ich weiß, dass dies alt ist, aber siehe diese Frage: stackoverflow.com/questions/4341739/…
NotSimon
1
@OvedD: siehe meine Antwort, wie man dies mit einem ModelForm
Hamish Downer
1
Es ist ziemlich dumm, dass Sie ein Widget angeben müssen, um einen Platzhalter hinzuzufügen. Sie sollten in der Lage sein, Widget-Attribute zu bearbeiten, ohne das gesamte Widget zu überschreiben ...
dspacejs
Für Chinesen benötigen Sie das vorhergehende u wie
folgt
60

Für eine ModelForm können Sie die Meta-Klasse folgendermaßen verwenden:

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
quelle
Beachten Sie, dass Sie in diesem Fall das Feld im Klassenkörper nicht angeben können.
Will S
Dies war die einfachste Methode für mich - und es war schön, dass alle anderen Attribute (dh erforderlich) immer noch automatisch hinzugefügt wurden, ohne dass ich sie angeben musste.
JxAxMxIxN
41

Die anderen Methoden sind alle gut. Wenn Sie das Feld jedoch nicht angeben möchten (z. B. für eine dynamische Methode), können Sie Folgendes verwenden:

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

Außerdem kann der Platzhalter für ModelForms mit der angegebenen Instanz von der Instanz abhängen.

Kennzeichen
quelle
7
Dies ist großartig, da nicht die langwierige Instanziierung von Widgets für kompliziertere Objekte wie z ModelMultipleChoiceField. Vielen Dank!
Donturner
1
Ähnliches gilt : for f in MyCommentForm.base_fields.values(): f.widget.attrs["placeholder"] = f.label, aber ich mag deine Konstruktormethode besser.
jozxyqk
21

Mit diesem Code können Sie Platzhalter attr für jedes TextInput-Feld in Ihrem Formular hinzufügen. Text für Platzhalter wird aus Modellfeldbezeichnungen entnommen.

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
Jewgenij Shchemelev
quelle
19

Gute Frage. Ich kenne drei Lösungen:

Lösung Nr. 1

Ersetzen Sie das Standard-Widget.

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

Lösung Nr. 2

Passen Sie das Standard-Widget an. Wenn Sie dasselbe Widget verwenden, das das Feld normalerweise verwendet, können Sie dieses einfach anpassen, anstatt ein völlig neues zu instanziieren.

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

Lösung Nr. 3

Wenn Sie mit einem Modellformular arbeiten, haben Sie ( zusätzlich zu den beiden vorherigen Lösungen ) die Möglichkeit, ein benutzerdefiniertes Widget für ein Feld anzugeben, indem Sie das widgetsAttribut der inneren MetaKlasse festlegen .

class CommentForm(forms.ModelForm):  
    class Meta:
        model = Comment
        widgets = {
            'body': forms.Textarea(attrs={'cols': 80, 'rows': 20})
        }
Dwayne Crooks
quelle
1
Ich wollte gerade eine Lösung als Ihre # 2 schreiben. Ich möchte hinzufügen, dass Sie Operationen auf alle Felder anwenden können, indem Sie sie self.fieldsfor field_name in self.fields: self.fields[field_name].widget.attrs.update({"placeholder": sth})
wiederholen
@ AlbertoChiusole Ja, das kannst du, wenn du das willst. Vielen Dank für den Hinweis.
Dwayne Crooks
@DwayneCrooks Ich schlage vor, Sie aktualisieren Ihre Nummer 3 gemäß der Lösung von cdosborn , da sie viel kürzer und besser lesbar ist.
Marian
1

Es ist unerwünscht, wissen zu müssen, wie ein Widget instanziiert wird, wenn Sie nur seinen Platzhalter überschreiben möchten.

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

Meistens möchte ich nur, dass alle Platzhalter dem ausführlichen Namen des in meinen Modellen definierten Felds entsprechen

Ich habe ein Mixin hinzugefügt, um dies einfach zu jeder Form zu machen, die ich erstelle.

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

Und

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
quelle
-2

Nachdem ich mir Ihre Methode angesehen hatte, benutzte ich diese Methode, um sie zu lösen.

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
quelle
2
Bitte beachten Sie, dass der Inhalt bei Stack Overflow auf Englisch sein muss. Abgesehen davon scheint dies eher ein "Ich auch" -Post zu sein als eine Antwort auf die oben gestellte Frage.
TylerH
Ich würde sagen, dass "ich auch" -Postings in Ordnung sind, wenn sie mehr Details hinzufügen. Was ist mit diesem Ansatz anders als mit den anderen? Was ist die Technik oder das wesentliche Lernen hier?
Halfer