无法使用 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>