Значення поля 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))

Відповіді:


135

Оскільки ви не передаєте дані POST, я вважаю, що те, що ви намагаєтеся зробити, це встановити початкове значення, яке відображатиметься у формі. Як це зробити з initialключовим словом.

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

Детальнішу інформацію див. У документах форми Django .

Якщо ви намагаєтесь змінити значення після надсилання форми, ви можете використовувати щось на зразок:

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

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


2
Це підтверджує те, що я знав, але мій ModelChoiceFieldвсе ще дає invalid_choice, коли я надаю йому initialзначення :(
markwalker_

Так, це теж моя проблема. І зміна form.data ['Email'] неможлива.
Гергелі Полонкай

2
я змінив шахту, form.data['Email'] = GetEmailString()і це працює
psychok7

1
Мені потрібно встановити його між CustomForm (request.POST) та .is_valid (), тому я не можу використовувати ні початкові в конструкторі, ні очищені_дані. Я спробував використовувати form.data, але це незмінне (Django 1.11).
Teekin

Правильне рішення цього питання повинно бути: дає доступ до форматувати значення навіть після інстанціірован вашої формиform.fields['Email'].initial = GetEmailString()form.fields['keyword'].initial
vctrd

95

Якщо ви вже ініціалізували форму, ви можете використовувати початкове властивість поля. Наприклад,

form = CustomForm()
form.fields["Email"].initial = GetEmailString()

Також чудово працює в циклі for for з набором форматів, просто використовуйте логіку "for form in formset", і ви можете встановити вибір та початкові дані, як показано вище.
radtek

5
Чи є інший спосіб зробити це Django 1.7 / Python 3.4? Це не працює для мене
Джеремі

1
@JeremyCraigMartinez: Ні ... Чи є форма, яку ви намагаєтеся зв'язати (з переданими даними GET / POST)? Документи кажуть. Тому початкові значення відображаються лише для незв'язаних форм. Для зв'язаних форм для виведення HTML будуть використані пов'язані дані. , дивіться тут
Маркус

9
правильний шлях - form.initial ["Електронна пошта"] = GetEmailString ()
Еліо Скордо

12

Якщо ви хочете зробити це в __init__методі форми з якоїсь причини, ви можете маніпулювати initialдіктом:

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'

Нарешті знайшов рішення. Дякую. Це працює для мене.
Almas Dusa

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? Це не працює для мене
Джеремі

3-й рядок може бути трохи коротшим, якщо не потрібно зберігати початкову форму:form.data = form.data.copy()
ZZY

@Josh, ось один сценарій необхідності: використовуйте форму для перевірки введення -> обробка з введенням -> обробка зроблена -> стерти / змінити декілька полів форми і надати HTML як відповідь. Наприклад, у формі є поля "ім'я", "електронна пошта", "вміст", я хочу зберегти "ім'я" та "електронна пошта", але стерти "вміст". Таким чином, користувачам не потрібно вводити ім’я / електронну пошту ще раз, якщо вони хочуть надіслати інший POST. Звичайно, ініціалізувати нову форму з тим самим іменем / електронною поштою, як початкове значення - це один спосіб, але я думаю, що стирання з старої форми в деяких випадках простіше
ZZY

Я не впевнений, що цілком розумію. Однак, якщо я це зробити, мені здається, що ви повинні, замість цього, використовувати modelform_factory. Таким чином ви можете створити клас форми, у якому немає полів, які ви не хочете. Дуже небезпечно мати клас Form, який містить поля, які не відображаються, оскільки об’єкт форми все одно прийматиме дані для нереалізованих полів. Зловмисник може використати це на свою користь.
Джош

5

Якщо ви ініціалізували подібну форму

form = CustomForm()

то правильним способом станом на січень 2019 року є використання .initialдля заміни даних. Це замінить дані в intialдиктаті, що йде разом із формою. Він також працює, якщо ви ініціалізувались із використанням якогось екземпляра, такого як 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

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">'

0

у віджеті використовуйте 'value' attr. Приклад:

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
Це для мене не вдається. У методі init у моїй формі є такий, як описаний вище , і він піднімає "AttributeError: Цей екземпляр QueryDict незмінний"
Джонатан Хартлі

Цей код працює лише тоді, коли форма була ініціалізована без будь-яких даних форми. Як результат, незмінний об'єкт на зразок request.GET або request.POST не буде пов'язаний, тому ви отримаєте порожній словник (form.data), який можна змінити без будь-яких помилок. FYI Я використовую Django 1.6.3
потар

Це спрацює, якщо для вашого заголовка "Тип вмісту" встановлено значення "багаточастинні / форми-дані". Він не працює, коли ви використовуєте тип вмісту "application / x-www-form-urlencoded". Я не знаю чому, але це було налагодження *****.
teewuane
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.