无法使用django在multipleChoiceField中获取发布数据

时间:2015-01-29 22:23:53

标签: python django django-forms

我有一个带有一些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;?

谢谢!

3 个答案:

答案 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>