Comment ajouter un espace réservé sur un CharField dans Django?

195

Prenez cette forme très simple, par exemple:

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

Cela est rendu dans le modèle:

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

Cependant, je veux ajouter l' placeholderattribut à ce champ avec une valeur de Searchsorte que le HTML ressemble à quelque chose comme:

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

De préférence, je voudrais transmettre la valeur de l'espace réservé à CharFielddans la classe de formulaire via un dictionnaire ou quelque chose comme:

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

Quelle serait la meilleure façon d'y parvenir?

Joelbitar
la source

Réponses:

281

Regardez la documentation des widgets . Fondamentalement, cela ressemblerait à:

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

Plus d'écriture, oui, mais la séparation permet une meilleure abstraction des cas plus compliqués.

Vous pouvez également déclarer un widgetsattribut contenant un <field name> => <widget instance>mappage directement sur le Metade votre ModelFormsous-classe.

Mike Axiak
la source
faut-il préciser forms.TextInputpour faire la attrs={'placeholder': 'Search'}déclaration?
JhovaniC
1
@OvedD, je sais que c'est vieux, mais voyez cette question: stackoverflow.com/questions/4341739/…
NotSimon
1
@OvedD: voir ma réponse pour savoir comment faire avec un ModelForm
Hamish Downer
1
C'est assez stupide de devoir spécifier un widget pour ajouter un espace réservé. Vous devriez être en mesure de modifier les attributs du widget sans
remplacer
Pour le chinois, vous avez besoin du précédent u comme ceci: {'placeholder': u '搜索'}
shellbye
60

Pour un ModelForm, vous pouvez utiliser la classe Meta ainsi:

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
la source
Notez que dans ce cas, vous ne pouvez pas spécifier le champ dans le corps de la classe.
Will S
C'était la méthode la plus simple pour moi - et c'était bien que tous les autres attributs (c'est-à-dire requis) soient toujours ajoutés automatiquement sans que je doive les spécifier.
JxAxMxIxN
41

Les autres méthodes sont toutes bonnes. Cependant, si vous préférez ne pas spécifier le champ (par exemple pour une méthode dynamique), vous pouvez utiliser ceci:

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

Il permet également à l'espace réservé de dépendre de l'instance de ModelForms avec l'instance spécifiée.

marque
la source
7
C'est génial car cela évite d'avoir à dupliquer la longue instanciation des widgets pour des objets plus complexes tels que ModelMultipleChoiceField. Merci!
donturner
1
Esprit similaire:, for f in MyCommentForm.base_fields.values(): f.widget.attrs["placeholder"] = f.labelmais j'aime mieux votre méthode constructeur.
jozxyqk
21

Vous pouvez utiliser ce code pour ajouter un attr d'espace réservé pour chaque champ TextInput de votre formulaire. Le texte des espaces réservés sera tiré des étiquettes de champ du modèle.

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
la source
19

Grande question. Je connais trois solutions:

Solution n ° 1

Remplacez le widget par défaut.

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

Solution n ° 2

Personnalisez le widget par défaut. Si vous utilisez le même widget que le champ utilise habituellement, vous pouvez simplement le personnaliser au lieu d'en instancier un entièrement nouveau.

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

Solution n ° 3

Enfin, si vous travaillez avec un formulaire modèle, vous avez la possibilité ( en plus des deux solutions précédentes ) de spécifier un widget personnalisé pour un champ en définissant l' widgetsattribut de la Metaclasse interne .

class CommentForm(forms.ModelForm):  
    class Meta:
        model = Comment
        widgets = {
            'body': forms.Textarea(attrs={'cols': 80, 'rows': 20})
        }
Dwayne Crooks
la source
1
J'étais sur le point d'écrire une solution comme la vôtre # 2. Je voudrais ajouter que vous pouvez appliquer des opérations sur tous les champs en itérant sur self.fields, par exemple:for field_name in self.fields: self.fields[field_name].widget.attrs.update({"placeholder": sth})
Alberto Chiusole
@AlbertoChiusole Oui, vous pouvez, si c'est ce que vous voulez faire. Merci de l'avoir signalé.
Dwayne Crooks
@DwayneCrooks Je vous suggère de mettre à jour votre # 3 selon la solution de cdosborn , car il est beaucoup plus court et plus lisible.
Marian
1

Il n'est pas souhaitable de savoir comment instancier un widget lorsque vous souhaitez simplement remplacer son espace réservé.

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

La plupart du temps, je souhaite simplement que tous les espaces réservés soient égaux au nom détaillé du champ défini dans mes modèles

J'ai ajouté un mixin pour le faire facilement dans n'importe quelle forme que je crée,

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

Et

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
la source
-2

Après avoir regardé votre méthode, j'ai utilisé cette méthode pour la résoudre.

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
la source
2
Veuillez noter que le contenu doit être en anglais sur Stack Overflow. En dehors de cela, cela semble être un message "moi aussi", plutôt qu'une réponse à la question posée ci-dessus.
TylerH
Je dirais que les messages "moi aussi" sont OK s'ils ajoutent plus de détails. Qu'en est-il de cette approche qui est différente des autres? Quelle est la technique ou l'apprentissage essentiel ici?
halfer le