【问题标题】:Unable to get post data in a multipleChoiceField with django无法使用 django 在 multipleChoiceField 中获取发布数据
【发布时间】:2015-03-29 08:00:29
【问题描述】:

我有一个带有一些复选框和一些文本的表单,当用户提交数据时,我使用以下表单对象:

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)

谁能告诉我我能做些什么来修复“cleaned_data”?

谢谢!

【问题讨论】:

  • 您的视图是什么样的?
  • 我刚刚更新了帖子

标签: python django django-forms


【解决方案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>

此代码更短、更惯用,并向用户提供验证反馈。

为了使其更短,您应该查看各种基于类的编辑视图,这些视图删除了许多表单处理样板。

【讨论】:

    【解决方案2】:

    在研究 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

    【讨论】:

      【解决方案3】:

      我最终得到了这段代码:

      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>
      

      【讨论】:

        猜你喜欢
        • 2012-11-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-03-20
        相关资源
        最近更新 更多