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