Como adiciono um espaço reservado a um CharField no Django?

195

Pegue este formulário muito simples, por exemplo:

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

Isso é renderizado no modelo:

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

No entanto, quero adicionar o placeholderatributo a este campo com um valor igual a, Searchpara que o HTML seja semelhante a:

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

De preferência, eu gostaria de passar o valor do espaço reservado para CharFielda classe form através de um dicionário ou algo como:

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

Qual seria a melhor maneira de conseguir isso?

Joelbitar
fonte

Respostas:

281

Veja a documentação dos widgets . Basicamente, seria parecido com:

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

Mais escrita, sim, mas a separação permite uma melhor abstração de casos mais complicados.

Você também pode declarar um widgetsatributo que contém um <field name> => <widget instance>mapeamento diretamente na Metasua ModelFormsubclasse.

Mike Axiak
fonte
você precisa especificar forms.TextInputpara fazer a attrs={'placeholder': 'Search'}declaração?
precisa
1
@OvedD, eu sei que isso é antigo, mas veja esta pergunta: stackoverflow.com/questions/4341739/…
NotSimon
1
@OvedD: ver a minha resposta para saber como fazer isso com um ModelForm
Hamish Downer
1
É muito estúpido que você precise especificar um widget para adicionar um espaço reservado. Você deve ser capaz de editar Widget atributos sem substituir todo o widget ...
dspacejs
Para os chineses, você precisa do u anterior: {'placeholder': u '搜索'}
shellbye
60

Para um ModelForm, você pode usar a classe Meta assim:

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
fonte
Observe que, nesse caso, você não pode especificar o campo no corpo da classe.
Will S
Este foi o método mais fácil para mim - e foi bom que todos os outros atributos (ou seja, necessários) ainda fossem adicionados automaticamente sem que eu tivesse que especificá-los.
JxAxMxIxN
41

Os outros métodos são todos bons. No entanto, se você preferir não especificar o campo (por exemplo, para algum método dinâmico), você pode usar isto:

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

Ele também permite que o espaço reservado dependa da instância para ModelForms com a instância especificada.

Marca
fonte
7
Isso é ótimo porque evita a duplicação da instanciação prolongada de widgets para objetos mais complicados, como ModelMultipleChoiceField. Obrigado!
precisa saber é o seguinte
1
Espírito semelhante:, for f in MyCommentForm.base_fields.values(): f.widget.attrs["placeholder"] = f.labelmas eu gosto mais do seu método construtor.
Jozxyqk
21

Você pode usar esse código para adicionar um espaço reservado para cada campo TextInput no formulário. O texto para espaços reservados será retirado dos rótulos dos campos do modelo.

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
fonte
19

Ótima pergunta. Existem três soluções que eu conheço:

Solução # 1

Substitua o widget padrão.

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

Solução # 2

Personalize o widget padrão. Se você estiver usando o mesmo widget que o campo normalmente usa, basta personalizá-lo em vez de instanciar um totalmente novo.

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

Solução # 3

Por fim, se você estiver trabalhando com um formulário de modelo ( além das duas soluções anteriores ), terá a opção de especificar um widget personalizado para um campo, definindo o widgetsatributo da Metaclasse interna .

class CommentForm(forms.ModelForm):  
    class Meta:
        model = Comment
        widgets = {
            'body': forms.Textarea(attrs={'cols': 80, 'rows': 20})
        }
Dwayne Crooks
fonte
1
Eu estava prestes a escrever uma solução como a sua # 2. Eu gostaria de acrescentar que você pode aplicar operações em todos os campos por iteração sobre self.fields, por exemplo:for field_name in self.fields: self.fields[field_name].widget.attrs.update({"placeholder": sth})
Alberto Chiusole
@AlbertoChiusole Sim, você pode, se é isso que deseja fazer. Obrigado por apontar isso.
Dwayne Crooks
@DwayneCrooks Eu sugiro que você atualize seu # 3 de acordo com a solução da cdosborn , porque é muito mais curto e mais legível.
Marian
1

É indesejável ter que saber como instanciar um widget quando você deseja substituir seu espaço reservado.

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

Na maioria das vezes, desejo apenas que todos os espaços reservados sejam iguais ao nome detalhado do campo definido em meus modelos

Adicionei um mixin para fazer isso facilmente em qualquer formulário que eu criar,

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

E

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

Depois de analisar seu método, usei esse método para resolvê-lo.

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
fonte
2
Observe que o conteúdo deve estar em inglês no Stack Overflow. Além disso, este parece ser um post "eu também", em vez de uma resposta à pergunta colocada acima.
TylerH
Eu diria que as mensagens "eu também" são válidas se adicionarem mais detalhes. E essa abordagem é diferente de qualquer uma das outras? Qual é a técnica ou aprendizado essencial aqui?
halfer