Django устанавливает значение поля после инициализации формы

116

Я пытаюсь установить для поля определенное значение после инициализации формы.

Например, у меня есть следующий класс.

class CustomForm(forms.Form):
    Email = forms.EmailField(min_length=1, max_length=200)

В представлении я хочу иметь возможность делать что-то вроде этого:

form = CustomForm()
form["Email"] = GetEmailString()

return HttpResponse(t.render(c))
Eldila
источник

Ответы:

135

Поскольку вы не передаете данные POST, я предполагаю, что вы пытаетесь установить начальное значение, которое будет отображаться в форме. Это можно сделать с помощью initialключевого слова.

form = CustomForm(initial={'Email': GetEmailString()})

Дополнительную информацию см. В документации Django Form .

Если вы пытаетесь изменить значение после отправки формы, вы можете использовать что-то вроде:

if form.is_valid():
    form.cleaned_data['Email'] = GetEmailString()

Проверьте указанные выше документы, чтобы узнать больше об использовании cleaned_data

Грант
источник
2
Это подтверждает то, что я знал, но мой по- ModelChoiceFieldпрежнему выдает invalid_choice, когда я даю ему initialзначение :(
markwalker_
Да, это тоже моя проблема. И изменение form.data ['Электронная почта'] невозможно.
ГергейПолонкай,
2
я поменял свой на, form.data['Email'] = GetEmailString()и он работает
psychok7
1
Мне нужно установить его между CustomForm (request.POST) и .is_valid (), поэтому я не могу использовать ни начальное значение в конструкторе, ни cleaned_data. Я пробовал использовать form.data, но он неизменен (Django 1.11).
Teekin 02
Правильное решение этого вопроса должно быть: дает доступ к инициализировать значения даже после инстанциирован вашей формыform.fields['Email'].initial = GetEmailString()form.fields['keyword'].initial
vctrd
95

Если вы уже инициализировали форму, вы можете использовать начальное свойство поля. Например,

form = CustomForm()
form.fields["Email"].initial = GetEmailString()
мистифицировать
источник
Также отлично работает в цикле for с набором форм, просто используйте логику «для формы в наборе форм», и вы можете установить варианты и начальные данные, как показано выше.
radtek
5
Есть ли другой способ сделать это - Django 1.7 / Python 3.4? Это не работает для меня
Джереми
1
@JeremyCraigMartinez: Нет ... Форма, которую вы пытаетесь использовать, является связанной формой (с переданными данными GET / POST)? В документации говорится, что именно поэтому начальные значения отображаются только для несвязанных форм. Для связанных форм в выводе HTML будут использоваться связанные данные. , см. здесь
Маркус
9
правильный способ - form.initial ["Email"] = GetEmailString ()
Элио Скордо,
12

Если вы __init__по какой-то причине хотите сделать это в методе формы , вы можете манипулировать initialdict:

class MyForm(forms.Form):
    my_field = forms.CharField(max_length=255)

    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
        self.initial['my_field'] = 'Initial value'
seddonym
источник
Наконец нашел решение. Спасибо. У меня это сработало.
Алмас Дусал
8

Что-то вроде Найджела Коэна будет работать, если вы добавляете данные в копию собранного набора данных формы:

form = FormType(request.POST)
if request.method == "POST":
    formcopy = form(request.POST.copy())
    formcopy.data['Email'] = GetEmailString()
Майло П
источник
1
Я не большой поклонник переопределения необработанных данных. Если вам это абсолютно необходимо, вам, вероятно, data[form.add_prefix('Email')]следует учесть случаи, когда установлен префикс.
Джош
2
Есть ли другой способ сделать это - Django 1.7 / Python 3.4? Это не работает для меня
Джереми
Третья строка может быть немного короче, если нет необходимости сохранять исходную форму:form.data = form.data.copy()
ZZY
@Josh, вот один сценарий необходимости: использовать форму для проверки ввода -> обработка с вводом -> обработка завершена -> стереть / изменить несколько полей формы и отобразить в HTML в качестве ответа. Например, в форме есть поля «имя», «электронная почта», «содержимое», я хочу сохранить «имя» и «адрес электронной почты», но стереть «содержимое». Так что пользователям не нужно снова вводить имя / адрес электронной почты, если они хотят отправить еще один POST. Конечно, инициализировать новую форму с тем же именем / адресом электронной почты, что и исходное значение, - это один из способов, но я думаю, что в некоторых случаях стереть старую форму проще
ZZY
Я не уверен, что полностью понимаю. Однако, если я это сделаю, мне кажется, что вы должны вместо этого использовать modelform_factory. Таким образом вы можете сгенерировать класс формы, в котором нет ненужных вам полей. Очень опасно иметь класс Form, у которого есть поля, которые не отображаются, поскольку объект формы все равно будет принимать данные для необработанных полей. Злоумышленник может использовать это в своих интересах.
Джош
5

Если вы инициализировали такую ​​форму

form = CustomForm()

то правильный способ с января 2019 года - использовать .initialдля замены данных. Это заменит данные в intialdict, который идет вместе с формой. Это также работает, если вы инициализировали какой-либо экземпляр, например form = CustomForm(instance=instance)

Чтобы заменить данные в форме, вам необходимо

form.initial['Email'] = GetEmailString()

Обобщая это было бы,

form.initial['field_name'] = new_value
Винит Сай
источник
3

Просто измените поле Form.data:

class ChooseProjectForm(forms.Form):
    project = forms.ModelChoiceField(queryset=project_qs)
    my_projects = forms.BooleanField()

    def __init__(self, *args, **kwargs):
        super(ChooseProjectForm, self).__init__(*args, **kwargs)
        self.data = self.data.copy()  # IMPORTANT, self.data is immutable
        # any condition:
        if self.data.get('my_projects'):
            my_projects = self.fields['project'].queryset.filter(my=True)
            self.fields['project'].queryset = my_projects
            self.fields['project'].initial = my_projects.first().pk
            self.fields['project'].empty_label = None  # disable "-----"
            self.data.update(project=my_projects.first().pk)  # Update Form data
            self.fields['project'].widget = forms.HiddenInput()  # Hide if you want
ckarrie
источник
0

Добавим еще один способ: это тоже работает, но с немного более современной нотацией. Это просто работает вокруг того факта, что a QueryDictнеизменяем.

>>> the_form.data = {**f.data.dict(), 'some_field': 47}
>>> the_form['some_field'].as_widget()
'<input type="hidden" name="some_field" value="47"
        class="field-some_field" id="id_some_field">'
др. Sybren
источник
0

в виджете используйте атрибут "значение". Пример:

username = forms.CharField(
    required=False,
    widget=forms.TextInput(attrs={'readonly': True, 'value': 'CONSTANT_VALUE'}),
)
Лукас Васкес
источник
-12

Другой способ сделать это, если вы уже инициализировали форму (с данными или без них) и вам необходимо добавить дополнительные данные перед их отображением:

form = Form(request.POST.form)
form.data['Email'] = GetEmailString()
Найджел Коэн
источник
8
Это не для меня. У меня есть строка, подобная приведенной выше, в методе инициализации моей формы , и она вызывает ошибку «AttributeError: этот экземпляр QueryDict является неизменным»
Джонатан Хартли
Этот код работает только тогда, когда форма была инициализирована без каких-либо данных формы. В результате неизменяемый объект, такой как request.GET или request.POST, не будет привязан, поэтому вы получите пустой словарь (form.data), который можно изменить без каких-либо ошибок. К вашему сведению, я использую Django 1.6.3
potar
Это будет работать, если ваш заголовок Content-Type установлен на multipart / form-data. Это не удается, когда вы используете тип содержимого «application / x-www-form-urlencoded». Не знаю почему, но отлаживать это было чертовски.
teewuane