Как добавить заполнитель на 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')

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

Joelbitar
источник

Ответы:

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"
cdosborn
источник
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"
        })
Iber L
источник
2
Обратите внимание, что содержимое должно быть на английском языке при переполнении стека. Кроме того, это, похоже, пост «я тоже», а не ответ на вопрос, поставленный выше.
TylerH
Я бы сказал, что сообщения "Я тоже" в порядке, если они добавляют больше деталей. Чем этот подход отличается от любого другого? Какая техника или необходимое обучение здесь?
halfer