我有一个带有一些checkBox和一些文本的表单,当用户提交数据时我使用下面的表单对象:
class PostForm(forms.Form):
product = forms.MultipleChoiceField(
label='product',
widget=forms.CheckboxSelectMultiple)
text = forms.CharField(label='text', max_length=1000)
def __init__(self, choices, *args, **kwargs):
super(PostForm, self).__init__(*args, **kwargs)
self.fields['product'].choices = choices
但是当我调试代码时,帖子cleaned_data
完全为空,data
对象包含所有数据:
<QueryDict: {'text': ['Hello world, this is a test\r\n'], 'product': ['7', '9'], 'csrfmiddlewaretoken': ['QYuwBoW3O5D42oScF2GzYuesTBIZZqRa']}>
更新
这里是模板:
<h1>Create post</h1>
<textarea rows="10" cols="50" name="text" form="post_form">
Hello world, this is a test
</textarea>
<form action="" method="post" id="post_form">
{% csrf_token %}
<label for="product_id" id="product_id">products: </label>
{% for product in products %}
<input type="checkbox" name="product" value="{{product.id}}">{{product.name}}
{% endfor %}
</select>
<br>
<input type="submit" value="OK">
</form>
这里有观点:
class PostView(AuthenticatedUserView):
template_name = 'trendby/post.html'
def get_if_authenticated(self, request, user):
products = models.Product.objects.filter(user=user)
return render(request, self.template_name, {'products': products})
def post_if_authenticated(self, request, user):
products = models.Product.objects.filter(user=user)
choices = []
for product in products:
choices += [str(product.id)]
form = PostForm(choices, request.POST)
if form.is_valid():
text = form.cleaned_data['text']
post = models.Post(text=text, user=user)
post.save()
return HttpResponse("Post: " + text)
return render(request, self.template_name)
有谁能告诉我怎么办才能解决`cleaning_data&#39;?
谢谢!
答案 0 :(得分:1)
该表单永远不会成功验证,因为选项必须是(id,name)对的列表。您正在发送一个简单的ID列表。由于您没有在模板上显示表单错误,因此隐藏了表单未保存的原因。
但是,您的方法在几个方面存在缺陷。实际上,您应该将ModelMultipleChoiceField与自定义查询集一起使用,而不是直接设置选项。您应该将无效表单发送到模板,并使用它来显示字段和错误。
class PostForm(forms.Form):
product = forms.ModelMultipleChoiceField(
label='product',
queryset=Post.objects.none())
text = forms.CharField(label='text', max_length=1000)
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
super(PostForm, self).__init__(*args, **kwargs)
self.fields['product'].queryset = Post.objects.filter(user=user)
class PostView(AuthenticatedUserView):
template_name = 'trendby/post.html'
def get_if_authenticated(self, request, user):
form = PostForm(user=user)
return render(request, self.template_name, {'form': form})
def post_if_authenticated(self, request, user):
form = PostForm(request.POST, user=user)
if form.is_valid():
text = form.cleaned_data['text']
post = models.Post(text=text, user=user)
post.save()
return HttpResponse("Post: " + text)
return render(request, self.template_name, {'form': form})
<form action="" method="post" id="post_form">
{% csrf_token %}
{{ form.products.label_tag }}
{{ form.products }}
{{ form.products.errors }}
<input type='submit'>
</form>
此代码更短,更惯用,并为用户提供验证反馈。
为了使它更短,您应该查看各种基于编辑类的视图,这些视图删除了大量的表单处理样板。
答案 1 :(得分:0)
经过一段时间研究django文档后,我接受了你的建议并更新了表单,现在代码更清晰了:
模特:
class Post(models.Model):
text = models.CharField(max_length=1000)
user = models.ForeignKey(User)
products = models.ManyToManyField(Product)
The From:
class PostForm(ModelForm):
class Meta:
model = models.Post
fields = ['text', 'products']
widgets = {
'text': Textarea(attrs={'cols': 80, 'rows': 10}),
}
这里有观点:
class PostView(AuthenticatedUserView):
template_name = 'trendby/post.html'
def get_if_authenticated(self, request, user):
PostSetForm = modelformset_factory(
models.Post,
form=PostForm)
formset = PostSetForm(queryset=models.Post.objects.none())
return render(request, self.template_name, {
"form": formset[0],
})
def post_if_authenticated(self, request, user):
PostFormSet = modelformset_factory(
models.Post,
form=PostForm)
formset = PostFormSet(request.POST)
if formset.is_valid():
post = formset.save(commit=False)[0]
post.user = user
post.save()
return HttpResponseRedirect(reverse('trendby:actions'))
return render(request, self.template_name)
最后,模板被更改:
<form method="post" action="">
{% csrf_token %}
{% for field in form %}
{{ field.label_tag }} {{ field }}<br>
{% endfor %}
<input type="submit" value="OK">
</form>
现在django创建了产品选择器,但是当我提交表单时,我收到以下错误:
Exception Type: ValidationError
Exception Value:
['ManagementForm data is missing or has been tampered with']
并且帖子数据只包含一个产品ID,它应该包含多个:
form-0-id
''
csrfmiddlewaretoken
'FIWwI9VW48lOjZLd7yT6vqtpK2IZaJ1K'
form-0-products
'2'
form-0-text
''
如何让它发送所有产品并修复ValidationError
?
答案 2 :(得分:0)
我最终使用此代码:
class PostForm(ModelForm):
class Meta:
model = models.Post
fields = ['text', 'products', 'image']
widgets = {
'text': Textarea(attrs={'cols': 80, 'rows': 10}),
'products': SelectMultiple(),
}
class PostView(AuthenticatedUserView):
template_name = 'myapp/post.html'
def get_if_authenticated(self, request, user):
form = PostForm()
return render(request, self.template_name, {"form": form})
def post_if_authenticated(self, request, user):
form = PostForm(request.POST, request.FILES)
if form.is_valid():
post = form.save(commit=False)
post.user = user
post.save()
return HttpResponseRedirect(reverse('myapp:actions'))
return render(request, self.template_name, {"form": form})
模板:
{% if form.errors %}<p><strong>{{ form.errors }}</strong></p>{% endif %}
<form method="post" enctype="multipart/form-data" action="">
{% csrf_token %}
{% for field in form %}
{{ field.label_tag }} {{ field }} <br>
{% endfor %}
<input type="submit" value="OK">
</form>