为什么这个 django formset 突然停止保存内容了?
Why this django formset has stopped saving the content all of a sudden?
我有这个视图在同一模板中呈现表单和表单集:
class LearnerUpdateView(LearnerProfileMixin, UpdateView):
model = User
form_class = UserForm
formset_class = LearnerFormSet
template_name = "formset_edit_learner.html"
success_url = reverse_lazy('pages:home')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
learner = User.objects.get(learner=self.request.user.learner)
formset = LearnerFormSet(instance=learner)
context["learner_formset"] = formset
return context
def get_object(self, queryset=None):
user = self.request.user
return user
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form_class = self.get_form_class()
form = self.get_form(form_class)
user = User.objects.get(learner=self.get_object().learner)
formsets = LearnerFormSet(self.request.POST, request.FILES, instance=user)
if form.is_valid():
for fs in formsets:
if fs.is_valid():
# Messages test start
messages.success(request, "Profile updated successfully!")
# Messages test end
fs.save()
else:
messages.error(request, "It didn't save!")
return self.form_valid(form)
return self.form_invalid(form)
然后我想让它更漂亮,我添加了 select2 multicheckbox 小部件和 django-bootstrap-datepicker-plus
其他地方没有任何变化,但是当我提交 post 它只保存与用户相关的数据而不是与学习者相关的数据(依赖于表单集)
根据消息,formset 数据未经验证,我不明白为什么,因为我根本没有接触实质,只接触了外观。
作为一个初学者我可能遗漏了一些重要的东西,我提前感谢任何能帮助我找出问题的人。
表格和模板如下:
(users.forms)
class LearnerForm(forms.ModelForm):
class Meta:
model = Learner
fields = ['locations', 'organization', 'supervisor', 'intro']
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ['username', 'first_name', 'last_name', 'birthday', 'email', 'profile_pic']
widgets = {
'birthday': DatePickerInput(format='%Y-%m-%d'), }
LearnerFormSet = inlineformset_factory(User, Learner, form=LearnerForm)
模板
{% extends '_base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<form action="" method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
{{ learner_formset.management_form}}
{% for form in learner_formset %}
{% if forloop.first %}
{% for field in form.visible_fields %}
{% if field.name != 'DELETE' %}
<label for="id_{{ field.name }}">{{ field.label|capfirst }}</label>
<div id='id_{{ field.name }}' class="form-group">
{{ field.errors.as_ul }}
{{ field }}
</div>
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
<input class="btn btn-success" type="submit" value="Update"/>
</form>
{% endblock content %}
我通过梳理之前的提交弄明白了。问题出在模板中,表单集未得到验证,因为我忽略了隐藏字段,我听说这是处理表单集时的常见问题。
所以正确的代码是这样的:
{% extends '_base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<form action="" method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
{{ learner_formset.management_form}}
{% for form in learner_formset %}
{% if forloop.first %}
{% comment %} This makes it so that it doesnt show the annoying DELETE checkbox {% endcomment %}
{% for field in form.visible_fields %}
{% if field.name != 'DELETE' %}
<label for="{{ field.name }}">{{ field.label|capfirst }}</label>
<div id="{{ field.name }}" class="form-group">
{{ field }}
{{ field.errors.as_ul }}
</div>
{% endif %}
{% endfor %}
{% endif %}
{% for field in form.visible_fields %}
{% if field.name == 'DELETE' %}
{{ field.as_hidden }}
{% else %}
{# Include the hidden fields in the form #}
{% if forloop.first %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
<input class="btn btn-success" type="submit" value="Update"/>
</form>
{% endblock content %}
我有这个视图在同一模板中呈现表单和表单集:
class LearnerUpdateView(LearnerProfileMixin, UpdateView):
model = User
form_class = UserForm
formset_class = LearnerFormSet
template_name = "formset_edit_learner.html"
success_url = reverse_lazy('pages:home')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
learner = User.objects.get(learner=self.request.user.learner)
formset = LearnerFormSet(instance=learner)
context["learner_formset"] = formset
return context
def get_object(self, queryset=None):
user = self.request.user
return user
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form_class = self.get_form_class()
form = self.get_form(form_class)
user = User.objects.get(learner=self.get_object().learner)
formsets = LearnerFormSet(self.request.POST, request.FILES, instance=user)
if form.is_valid():
for fs in formsets:
if fs.is_valid():
# Messages test start
messages.success(request, "Profile updated successfully!")
# Messages test end
fs.save()
else:
messages.error(request, "It didn't save!")
return self.form_valid(form)
return self.form_invalid(form)
然后我想让它更漂亮,我添加了 select2 multicheckbox 小部件和 django-bootstrap-datepicker-plus
其他地方没有任何变化,但是当我提交 post 它只保存与用户相关的数据而不是与学习者相关的数据(依赖于表单集)
根据消息,formset 数据未经验证,我不明白为什么,因为我根本没有接触实质,只接触了外观。
作为一个初学者我可能遗漏了一些重要的东西,我提前感谢任何能帮助我找出问题的人。
表格和模板如下:
(users.forms)
class LearnerForm(forms.ModelForm):
class Meta:
model = Learner
fields = ['locations', 'organization', 'supervisor', 'intro']
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ['username', 'first_name', 'last_name', 'birthday', 'email', 'profile_pic']
widgets = {
'birthday': DatePickerInput(format='%Y-%m-%d'), }
LearnerFormSet = inlineformset_factory(User, Learner, form=LearnerForm)
模板
{% extends '_base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<form action="" method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
{{ learner_formset.management_form}}
{% for form in learner_formset %}
{% if forloop.first %}
{% for field in form.visible_fields %}
{% if field.name != 'DELETE' %}
<label for="id_{{ field.name }}">{{ field.label|capfirst }}</label>
<div id='id_{{ field.name }}' class="form-group">
{{ field.errors.as_ul }}
{{ field }}
</div>
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
<input class="btn btn-success" type="submit" value="Update"/>
</form>
{% endblock content %}
我通过梳理之前的提交弄明白了。问题出在模板中,表单集未得到验证,因为我忽略了隐藏字段,我听说这是处理表单集时的常见问题。
所以正确的代码是这样的:
{% extends '_base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<form action="" method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
{{ learner_formset.management_form}}
{% for form in learner_formset %}
{% if forloop.first %}
{% comment %} This makes it so that it doesnt show the annoying DELETE checkbox {% endcomment %}
{% for field in form.visible_fields %}
{% if field.name != 'DELETE' %}
<label for="{{ field.name }}">{{ field.label|capfirst }}</label>
<div id="{{ field.name }}" class="form-group">
{{ field }}
{{ field.errors.as_ul }}
</div>
{% endif %}
{% endfor %}
{% endif %}
{% for field in form.visible_fields %}
{% if field.name == 'DELETE' %}
{{ field.as_hidden }}
{% else %}
{# Include the hidden fields in the form #}
{% if forloop.first %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
{% endif %}
{% endfor %}
{% endfor %}
<input class="btn btn-success" type="submit" value="Update"/>
</form>
{% endblock content %}