如何在成功的POST请求后更改Class-Based-Views的表单字段填充?

huangapple go评论102阅读模式
英文:

How can I change form field population *after* successful POST request for Class-Based-Views

问题

  1. # forms.py
  2. class CalculatorForm(forms.Form):
  3. body_weight = forms.FloatField(required=False)
  4. def clean(self):
  5. cleaned_data = super().clean()
  6. if cleaned_data['body_weight'] is None:
  7. cleaned_data['body_weight'] = 50.0
  8. return cleaned_data
  1. # views.py
  2. class CalculatorView(FormView):
  3. template_name = 'myapp/mycalculator.html'
  4. form_class = CalculatorForm
  5. def get_context_data(self, res=None, **kwargs):
  6. context = super().get_context_data(**kwargs)
  7. if res is not None:
  8. context['result'] = res
  9. return context
  10. def form_valid(self, form, *args, **kwargs):
  11. res = form.cleaned_data['body_weight'] / 2
  12. return render(
  13. self.request,
  14. self.template_name,
  15. context=self.get_context_data(res=res, **kwargs)
  16. )
英文:

I want to change the forms initial field population. Here is the catch: I want to change it for the POST request and not for the GET request.

Let's say my app offers a calculation based on a body weight input. If the user inputs a body weight calculation happens with that weight, if not a default of 50 is used. So it is allowed to let the field empty. But after the calculation ran, I want to display that the value used for calculation was 50. That's why I want to populate the field with 50 after the form was initially submitted with an empty value.

  1. # forms.py
  2. class CalculatorForm(forms.Form):
  3. body_weight = forms.FloatField(required=False)
  4. def clean(self):
  5. cleaned_data = super().clean()
  6. if cleaned_data['body_weight'] is None:
  7. cleaned_data['body_weight'] = 50.0
  8. # ideally I want to put the logic here
  9. # self.data[bpka] = 50.0 --> AttributeError: This QueryDict instance is immutable
  10. # self.fields['body_weight'] = 50.0 --> does not work
  11. # self.initial.update({'body_weight': 50.0}) --> does not work
  12. return cleaned_data

I feel like the problem is that I can not reach the bound fields from the clean() method.

If it is not possible within the form the logic has to go to the view I guess. Feel free to modify here:

  1. class CalculatorView(FormView):
  2. template_name = 'myapp/mycalculator.html'
  3. form_class = CalculatorForm
  4. def get_context_data(self, res=None, **kwargs):
  5. context = super().get_context_data(**kwargs)
  6. if res is not None:
  7. context['result'] = res
  8. return context
  9. def form_valid(self, form, *args, **kwargs):
  10. # form['body_weight'] = 50.0 --> does not work
  11. res = form.cleaned_data['body_weight'] / 2
  12. return render(
  13. self.request,
  14. self.template_name,
  15. context=self.get_context_data(res=res, **kwargs)
  16. )

答案1

得分: 1

你可以重写 .form_valid 方法,因为该方法在提交有效的表单数据时被调用。通过这种方式,创建一个带有所需 initial 值的新实例 CalculatorForm,而不是返回默认的 HttpResponseRedirect,而是使用新表单渲染页面。

保留你的表单的 clean 方法不变,然后将修改后的 form.cleaned_data 作为新实例化表单的初始字典传递。

forms.py

  1. class CalculatorForm(forms.Form):
  2. body_weight = forms.FloatField(required=False)
  3. def clean(self):
  4. cleaned_data = super().clean()
  5. if cleaned_data['body_weight'] is None:
  6. cleaned_data['body_weight'] = 50.0
  7. return cleaned_data

views.py

  1. class CalculatorView(FormView):
  2. template_name = "myapp/mycalculator.html"
  3. form_class = CalculatorForm
  4. def get_context_data(self, res=None, **kwargs):
  5. context = super().get_context_data(**kwargs)
  6. if res is not None:
  7. context['result'] = res
  8. return context
  9. def form_valid(self, form):
  10. body_weight = form.cleaned_data["body_weight"]
  11. res = body_weight / 2
  12. form = self.form_class(initial=form.cleaned_data)
  13. return render(
  14. self.request,
  15. self.template_name,
  16. context=self.get_context_data(res=res, form=form, **kwargs)
  17. )

myapp/mycalculator.html

  1. <body>
  2. <form action="{% url 'calculator' %}" method="post">
  3. {% csrf_token %}
  4. {{ form }}
  5. <button type="submit">Send</button>
  6. </form>
  7. {% if result %}
  8. <p>{{ result }}</p>
  9. {% endif %}
  10. </body>
英文:

You can override .form_valid since the method is called when valid form data has been POSTed. In this way creating a new instance of CalculatorForm with the desired initial value and instead of returning a HttpResponseRedirect which is default render the page with the new form.

Keep the clean method of your form as is and then pass the modified form.cleaned_data as the initial dict for your newly instantiated form.

forms.py

  1. class CalculatorForm(forms.Form):
  2. body_weight = forms.FloatField(required=False)
  3. def clean(self):
  4. cleaned_data = super().clean()
  5. if cleaned_data[&#39;body_weight&#39;] is None:
  6. cleaned_data[&#39;body_weight&#39;] = 50.0
  7. return cleaned_data

views.py

  1. class CalculatorView(FormView):
  2. template_name = &quot;myapp/mycalculator.html&quot;
  3. form_class = CalculatorForm
  4. def get_context_data(self, res=None, **kwargs):
  5. context = super().get_context_data(**kwargs)
  6. if res is not None:
  7. context[&#39;result&#39;] = res
  8. return context
  9. def form_valid(self, form):
  10. body_weight = form.cleaned_data[&quot;body_weight&quot;]
  11. res = body_weight / 2
  12. form = self.form_class(initial=form.cleaned_data)
  13. return render(
  14. self.request,
  15. self.template_name,
  16. context=self.get_context_data(res=res, form=form, **kwargs)
  17. )

myapp/mycalculator.html

  1. &lt;body&gt;
  2. &lt;form action=&quot;{% url &#39;calculator&#39; %}&quot; method=&quot;post&quot;&gt;
  3. {% csrf_token %}
  4. {{ form }}
  5. &lt;button type=&quot;submit&quot;&gt;Send&lt;/button&gt;
  6. &lt;/form&gt;
  7. {% if result %}
  8. &lt;p&gt;{{ result }}&lt;/p&gt;
  9. {% endif %}
  10. &lt;/body&gt;

huangapple
  • 本文由 发表于 2023年6月29日 22:12:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/76581885.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定