¿Cómo agrego un marcador de posición en un CharField en Django?

195

Tome esta forma muy simple, por ejemplo:

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

Esto se representa en la plantilla:

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

Sin embargo, quiero agregar el placeholderatributo a este campo con un valor de Searchpara que el HTML se vea así:

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

Preferiblemente me gustaría pasar el valor del marcador de posición a CharFieldla clase de formulario a través de un diccionario o algo así como:

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

¿Cuál sería la mejor manera de lograr esto?

Joelbitar
fuente

Respuestas:

281

Mira la documentación de los widgets . Básicamente se vería así:

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

Más escritura, sí, pero la separación permite una mejor abstracción de casos más complicados.

También puede declarar un widgetsatributo que contiene una <field name> => <widget instance>asignación directamente en Metasu ModelFormsubclase.

Mike Axiak
fuente
¿necesita especificar forms.TextInputpara hacer la attrs={'placeholder': 'Search'}declaración?
JhovaniC
1
@OvedD, sé que esto es viejo, pero vea esta pregunta: stackoverflow.com/questions/4341739/…
NotSimon
1
@OvedD: vea mi respuesta sobre cómo hacer esto con un ModelForm
Hamish Downer
1
Es bastante estúpido que tengas que especificar un widget para agregar un marcador de posición. Debería poder editar los atributos del widget sin anular todo el widget ...
dspacejs
Para el chino, necesita el precedente u así: {'placeholder': u '搜索'}
shellbye
60

Para un ModelForm, puede usar la clase Meta así:

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
fuente
Tenga en cuenta que en este caso no puede especificar el campo en el cuerpo de la clase.
Will S
Este fue el método más fácil para mí, y fue bueno que todos los demás atributos (es decir, obligatorios) todavía se agregaran automáticamente sin tener que especificarlos.
JxAxMxIxN
41

Los otros métodos son todos buenos. Sin embargo, si prefiere no especificar el campo (por ejemplo, para algún método dinámico), puede usar esto:

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

También permite que el marcador de posición dependa de la instancia de ModelForms con la instancia especificada.

marca
fuente
77
Esto es genial porque evita tener que duplicar la larga creación de instancias de widgets para objetos más complicados como ModelMultipleChoiceField. ¡Gracias!
donturner
1
Espíritu similar: for f in MyCommentForm.base_fields.values(): f.widget.attrs["placeholder"] = f.labelpero me gusta más tu método de construcción.
jozxyqk
21

Puede usar este código para agregar el atributo de marcador de posición para cada campo TextInput en su formulario. El texto para los marcadores de posición se tomará de las etiquetas de campo del 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
fuente
19

Gran pregunta Hay tres soluciones que conozco:

Solución n. ° 1

Reemplace el widget predeterminado.

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

Solución n. ° 2

Personaliza el widget predeterminado. Si está utilizando el mismo widget que el campo generalmente usa, simplemente puede personalizarlo en lugar de crear una instancia completamente nueva.

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

Solución # 3

Finalmente, si está trabajando con un formulario modelo, entonces ( además de las dos soluciones anteriores ) tiene la opción de especificar un widget personalizado para un campo configurando el widgetsatributo de la Metaclase interna .

class CommentForm(forms.ModelForm):  
    class Meta:
        model = Comment
        widgets = {
            'body': forms.Textarea(attrs={'cols': 80, 'rows': 20})
        }
Dwayne Crooks
fuente
1
Estaba a punto de escribir una solución como la suya # 2. Me gustaría agregar que puede aplicar operaciones en todos los campos iterando self.fields, por ejemplo:for field_name in self.fields: self.fields[field_name].widget.attrs.update({"placeholder": sth})
Alberto Chiusole
@AlbertoChiusole Sí, puedes, si eso es lo que quieres hacer. Gracias por mencionarlo.
Dwayne Crooks
@DwayneCrooks Le sugiero que actualice su # 3 según la solución de cdosborn , porque es mucho más corto y más legible.
Marian
1

No es deseable tener que saber cómo crear una instancia de un widget cuando solo desea anular su marcador de posición.

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

La mayoría de las veces solo deseo tener todos los marcadores de posición iguales al nombre detallado del campo definido en mis modelos

Agregué un mixin para hacer esto fácilmente a cualquier forma que cree,

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

Y

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

Después de mirar su método, utilicé este método para resolverlo.

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
fuente
2
Tenga en cuenta que el contenido debe estar en inglés en Stack Overflow. Aparte de eso, esto parece ser una publicación "yo también", en lugar de una respuesta a la pregunta planteada anteriormente.
TylerH
Diría que las publicaciones "yo también" están bien si agregan más detalles. ¿Qué pasa con este enfoque es diferente a cualquiera de los otros? ¿Cuál es la técnica o el aprendizaje esencial aquí?
halfer