Как добавить поле формы Django динамически в зависимости от того, было ли заполнено предыдущее поле?
У меня есть форма (Formset) для обновления пользователями своих профилей. Это стандартная форма модели User, и пользовательская форма модели Participants. Теперь, в случаях, когда участник предоставляет свой номер телефона, мне нужно обновить всю форму с новым "Кодом", введенным динамически. И участник будет вводить код, который он получил в SMS. Вот как я пытаюсь это сделать:
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
form.save()
seller_form = SellerForm(self.request.POST, instance=self.object.seller)
if seller_form.is_valid():
seller = self.request.user.seller
seller.inn = seller_form.cleaned_data.get('inn')
if seller_form.cleaned_data.get('phone_number'):
seller_form.fields['code'] = models.CharField(max_length=4)
return render(request, self.template_name, {'form': form, 'seller_form': seller_form})
seller.save()
return HttpResponse('Seller updated')
return render(request, self.template_name, {'form': form, 'seller_form': seller_form})
Я не уверен, что это тот способ, которым я могу добавить дополнительное поле. Что бы вы предложили для решения этой ситуации?
Используемая мной техника заключается в том, что первоначально поле на форме скрыто. Когда форма становится действительной, я заставляю его стать видимым, а затем снова отправляю форму. В представлениях на основе классов и контура:
class SomeThingForm( forms.Modelform):
class Meta:
model=Thing
fields = [ ...
confirm = forms.BooleanField(
initial=False, required=False, widget=forms.widgets.HiddenInput,
label='Confirm your inputs?' )
class SomeView( CreateView): # or UpdateView
form_class = SomeThingForm
template_name = 'whatever'
def form_valid( self, form):
_warnings = []
# have a look at cleaned_data
# generate _warnings (a list of 2-tuples) about things which
# aren't automatically bad data but merit another look
if not form.cleaned_data['confirm'] and _warnings:
form.add_error('confirm', 'Correct possible typos and override if sure')
for field,error_text in _warnings:
form.add_error( field, error_text) # 'foo', 'Check me'
# make the confirm field visible
form.fields['confirm'].widget = forms.widgets.Select(
choices=((0, 'No'), (1, 'Yes')) )
# treat the form as invalid (which it now is!)
return self.form_invalid( form)
# OK it's come back with confirm=True
form.save() # save the model
return redirect( ...)
Для этого вопроса, я думаю, вы замените confirm на sms_challenge, Charfield или IntegerField, изначально скрытый, со значением по умолчанию, которое никогда не будет правильным ответом. Когда остальная часть формы пройдет проверку, будет вызвано form_valid(), а затем тот же поток программы, за исключением того, что вы также отправляете SMS на номер телефона в clean_data.
_warnings = []
# retrieve sms_challenge that was sent
if form.cleaned_data['sms_challenge'] != sms_challenge:
_warnings.append( ['sms_challenge', 'Sorry, that's not right'] )
if _warnings:
...
form.fields['sms_challenge'].widget = forms.widgets.TextInput
return self.form_invalid( form)
Думаю, это должно сработать.