无法使用 django 在 multipleChoiceField 中获取 post 数据
Unable to get post data in a multipleChoiceField with django
我有一个带有一些复选框和一些文本的表单,当用户提交数据时我使用以下表单对象:
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
但是当我调试代码时,post 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)
谁能告诉我如何修复“cleaned_data”?
谢谢!
该表单永远不会成功验证,因为选择必须是 (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>
此代码更短、更惯用,并向用户提供验证反馈。
为了使其更短,您应该查看各种基于编辑 class 的视图,这些视图删除了大量表单处理样板。
在研究了一段时间的django文档后,我采纳了你的建议并更新了表格,现在代码更清晰了:
型号:
class Post(models.Model):
text = models.CharField(max_length=1000)
user = models.ForeignKey(User)
products = models.ManyToManyField(Product)
发件人:
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']
而post数据只包含一个产品id,应该包含多个:
form-0-id
''
csrfmiddlewaretoken
'FIWwI9VW48lOjZLd7yT6vqtpK2IZaJ1K'
form-0-products
'2'
form-0-text
''
如何发送所有产品并修复 ValidationError
?
我最终使用这段代码工作:
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>
我有一个带有一些复选框和一些文本的表单,当用户提交数据时我使用以下表单对象:
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
但是当我调试代码时,post 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)
谁能告诉我如何修复“cleaned_data”?
谢谢!
该表单永远不会成功验证,因为选择必须是 (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>
此代码更短、更惯用,并向用户提供验证反馈。
为了使其更短,您应该查看各种基于编辑 class 的视图,这些视图删除了大量表单处理样板。
在研究了一段时间的django文档后,我采纳了你的建议并更新了表格,现在代码更清晰了:
型号:
class Post(models.Model):
text = models.CharField(max_length=1000)
user = models.ForeignKey(User)
products = models.ManyToManyField(Product)
发件人:
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']
而post数据只包含一个产品id,应该包含多个:
form-0-id
''
csrfmiddlewaretoken
'FIWwI9VW48lOjZLd7yT6vqtpK2IZaJ1K'
form-0-products
'2'
form-0-text
''
如何发送所有产品并修复 ValidationError
?
我最终使用这段代码工作:
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>