英文:
How can I change form field population *after* successful POST request for Class-Based-Views
问题
# forms.py
class CalculatorForm(forms.Form):
body_weight = forms.FloatField(required=False)
def clean(self):
cleaned_data = super().clean()
if cleaned_data['body_weight'] is None:
cleaned_data['body_weight'] = 50.0
return cleaned_data
# views.py
class CalculatorView(FormView):
template_name = 'myapp/mycalculator.html'
form_class = CalculatorForm
def get_context_data(self, res=None, **kwargs):
context = super().get_context_data(**kwargs)
if res is not None:
context['result'] = res
return context
def form_valid(self, form, *args, **kwargs):
res = form.cleaned_data['body_weight'] / 2
return render(
self.request,
self.template_name,
context=self.get_context_data(res=res, **kwargs)
)
英文:
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.
# forms.py
class CalculatorForm(forms.Form):
body_weight = forms.FloatField(required=False)
def clean(self):
cleaned_data = super().clean()
if cleaned_data['body_weight'] is None:
cleaned_data['body_weight'] = 50.0
# ideally I want to put the logic here
# self.data[bpka] = 50.0 --> AttributeError: This QueryDict instance is immutable
# self.fields['body_weight'] = 50.0 --> does not work
# self.initial.update({'body_weight': 50.0}) --> does not work
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:
class CalculatorView(FormView):
template_name = 'myapp/mycalculator.html'
form_class = CalculatorForm
def get_context_data(self, res=None, **kwargs):
context = super().get_context_data(**kwargs)
if res is not None:
context['result'] = res
return context
def form_valid(self, form, *args, **kwargs):
# form['body_weight'] = 50.0 --> does not work
res = form.cleaned_data['body_weight'] / 2
return render(
self.request,
self.template_name,
context=self.get_context_data(res=res, **kwargs)
)
答案1
得分: 1
你可以重写 .form_valid
方法,因为该方法在提交有效的表单数据时被调用。通过这种方式,创建一个带有所需 initial
值的新实例 CalculatorForm
,而不是返回默认的 HttpResponseRedirect
,而是使用新表单渲染页面。
保留你的表单的 clean
方法不变,然后将修改后的 form.cleaned_data
作为新实例化表单的初始字典传递。
forms.py
class CalculatorForm(forms.Form):
body_weight = forms.FloatField(required=False)
def clean(self):
cleaned_data = super().clean()
if cleaned_data['body_weight'] is None:
cleaned_data['body_weight'] = 50.0
return cleaned_data
views.py
class CalculatorView(FormView):
template_name = "myapp/mycalculator.html"
form_class = CalculatorForm
def get_context_data(self, res=None, **kwargs):
context = super().get_context_data(**kwargs)
if res is not None:
context['result'] = res
return context
def form_valid(self, form):
body_weight = form.cleaned_data["body_weight"]
res = body_weight / 2
form = self.form_class(initial=form.cleaned_data)
return render(
self.request,
self.template_name,
context=self.get_context_data(res=res, form=form, **kwargs)
)
myapp/mycalculator.html
<body>
<form action="{% url 'calculator' %}" method="post">
{% csrf_token %}
{{ form }}
<button type="submit">Send</button>
</form>
{% if result %}
<p>{{ result }}</p>
{% endif %}
</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
class CalculatorForm(forms.Form):
body_weight = forms.FloatField(required=False)
def clean(self):
cleaned_data = super().clean()
if cleaned_data['body_weight'] is None:
cleaned_data['body_weight'] = 50.0
return cleaned_data
views.py
class CalculatorView(FormView):
template_name = "myapp/mycalculator.html"
form_class = CalculatorForm
def get_context_data(self, res=None, **kwargs):
context = super().get_context_data(**kwargs)
if res is not None:
context['result'] = res
return context
def form_valid(self, form):
body_weight = form.cleaned_data["body_weight"]
res = body_weight / 2
form = self.form_class(initial=form.cleaned_data)
return render(
self.request,
self.template_name,
context=self.get_context_data(res=res, form=form, **kwargs)
)
myapp/mycalculator.html
<body>
<form action="{% url 'calculator' %}" method="post">
{% csrf_token %}
{{ form }}
<button type="submit">Send</button>
</form>
{% if result %}
<p>{{ result }}</p>
{% endif %}
</body>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论