Как добавить заполнитель на CharField в Django?


195

Возьмите эту очень простую форму, например:

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

Это отображается в шаблоне:

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

Однако я хочу добавить placeholderатрибут в это поле со значением, Searchчтобы HTML выглядел примерно так:

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

Предпочтительно, я хотел бы передать значение заполнителя в CharFieldкласс формы через словарь или что-то вроде:

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

Каков наилучший способ сделать это?

Ответы:


282

Посмотрите документацию по виджетам . В основном это будет выглядеть так:

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

Да, больше написания, но разделение позволяет лучше абстрагироваться от более сложных случаев.

Вы также можете объявить widgetsатрибут, содержащий <field name> => <widget instance>сопоставление, непосредственно в Metaвашем ModelFormподклассе.


вам нужно указать, forms.TextInputчтобы сделать attrs={'placeholder': 'Search'}декларацию?
— JhovaniC

1
@OvedD, я знаю, что это старый, но вижу этот вопрос: stackoverflow.com/questions/4341739/…
— NotSimon

1
@OvedD: см. Мой ответ о том, как это сделать с помощью ModelForm
— Хэмиш Даунер

1
Довольно глупо, что вам нужно указать виджет для добавления заполнителя. Вы должны иметь возможность редактировать атрибуты виджета без переопределения всего виджета ...
— dspacejs

Для китайского языка вам нужен предыдущий u, например: {'placeholder': u '搜索'}
— shellbye

60

Для ModelForm вы можете использовать класс Meta таким образом:

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

Обратите внимание, что в этом случае вы не можете указать поле в теле класса.
— Будет ли S

Для меня это был самый простой способ - и было приятно, что все остальные атрибуты (т.е. обязательные) все равно добавлялись автоматически, и мне не нужно было их указывать.
— JxAxMxIxN

41

Все остальные методы хороши. Однако, если вы предпочитаете не указывать поле (например, для некоторого динамического метода), вы можете использовать это:

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

Это также позволяет заполнителю зависеть от экземпляра для ModelForms с указанным экземпляром.


7
Это замечательно, потому что позволяет избежать дублирования длинных экземпляров виджетов для более сложных объектов, таких как ModelMultipleChoiceField. Спасибо!
— donturner

1
Подобный дух for f in MyCommentForm.base_fields.values(): f.widget.attrs["placeholder"] = f.label, но мне больше нравится ваш метод конструктора.
— Jozxyqk

21

Этот код можно использовать для добавления атрибута заполнителя для каждого поля TextInput в форме. Текст для заполнителей будет взят из меток полей модели.

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

20

Отличный вопрос Есть три решения, о которых я знаю:

Решение № 1

Заменить виджет по умолчанию.

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

Решение № 2

Настройте виджет по умолчанию. Если вы используете тот же виджет, который обычно используется в этом поле, вы можете просто настроить его вместо создания совершенно нового.

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

Решение № 3

Наконец, если вы работаете с формой модели, то ( в дополнение к двум предыдущим решениям ) у вас есть возможность указать собственный виджет для поля, установив widgetsатрибут внутреннего Metaкласса.

class CommentForm(forms.ModelForm):  
    class Meta:
        model = Comment
        widgets = {
            'body': forms.Textarea(attrs={'cols': 80, 'rows': 20})
        }

1
Я собирался написать решение как ваше # 2. Я хотел бы добавить, что вы можете применять операции ко всем полям, повторяя self.fields, например:for field_name in self.fields: self.fields[field_name].widget.attrs.update({"placeholder": sth})
— Альберто Кьюзол

@AlbertoChiusole Да, вы можете, если это то, что вы хотите сделать. Спасибо за указание на это.
— Дуэйн Крукс

@DwayneCrooks Я предлагаю вам обновить # 3 в соответствии с решением cdosborn , потому что оно намного короче и более читабельно.
— Мариан

1

Нежелательно знать, как создавать экземпляр виджета, когда вы просто хотите переопределить его заполнитель.

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

0

В большинстве случаев я просто хочу, чтобы все заполнители были равны подробному названию поля, определенного в моих моделях

Я добавил миксин, чтобы легко сделать это для любой формы, которую я создаю,

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

И

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

-2

Посмотрев на ваш метод, я использовал этот метод для его решения.

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

2
Обратите внимание, что содержимое должно быть на английском языке при переполнении стека. Кроме того, это, похоже, пост «я тоже», а не ответ на вопрос, поставленный выше.
— TylerH

Я бы сказал, что сообщения "Я тоже" в порядке, если они добавляют больше деталей. Чем этот подход отличается от любого другого? Какая техника или необходимое обучение здесь?
— halfer
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.