Django - 需要可选的表单字段

时间:2018-05-27 05:58:30

标签: django forms optional

这里有一些新的Django用户。我有一个模型和表单,我打算允许用户在上传(发布,如果使用模型名称)图像,文本或两者之间进行选择。尽管image属性为blank = True且null = True,但在没有图像的情况下不允许上载。然后我在表单的图像部分设置required = False,但这导致了

MultiValueDictKeyError

我的模特是:

class Post(models.Model):
    image = models.ImageField(upload_to='uploaded_images', blank=True, 
    null=True)
    text_post = models.CharField(max_length=1000)
    author = models.ForeignKey(User)

我的表格是:

class PostForm(forms.ModelForm):
    image = forms.FileField(required=False, label='Select an image 
    file', 
    help_text='Please select a photo to upload')
    text_post = forms.CharField(help_text="Please enter some text.") 
    class Meta:
        model = Post
        fields = ('image', 'text_post',)
        exclude = ('author',)

我的观点是:

def posts(request, id=None):
    neighborhood = get_object_or_404(Neighborhood, id=id)
    form = PostForm()
    if request.method == 'POST':
        form = PostForm(request.POST, request.FILES)
        if form.is_valid():
            post = Post(image = request.FILES['image'])
            post = form.save(commit=False)
            post.author = request.user
            post = post.save()
            next = request.POST.get('next', '/')
            return HttpResponseRedirect(next)
    else:
        form = PostForm()
        posts = Post.objects.all().order_by('-id')
        return render(request, 'posts.html', context = {'form':form, 
        'posts':posts, 'neighborhood':neighborhood})

我的表格是:

    <form id="PostForm" method="post" action="/view/{{ neighborhood.id }}/posts/" enctype="multipart/form-data">

        {% csrf_token %}
        {% for hidden in form.hidden_fields %}
            {{ hidden }}
        {% endfor %}

        {% for field in form.visible_fields %}
            {{ field.errors }}
            {{ field.help_text }}
            {{ field }}
        {% endfor %}
        <input type="hidden" name="next" value="{{ request.path }}">
        <input type="submit" name="submit" value="Post" />
    </form>    

1 个答案:

答案 0 :(得分:1)

在您提供有关错误的更多信息之前,我将对此进行一次破解并说明问题来自您认为的这一行:

post = Post(image = request.FILES['image'])

由于您提到图片可以被视为可选图片,因此当您提交有效的文字帖子时会产生问题,但您对request.FILES的调用将失败。

如果您不确定某个密钥是否存在于dict中(就像您在这种情况下一样),则可以使用get方法提供默认值(如果它不存在)。您可以将此行重构为:

post = Post(image = request.FILES.get('image')

默认情况下,get方法在无法找到密钥时会返回None

总而言之,您的观点有点令人困惑。你准备带有图片的帖子(你从未在其上调用.save()),但是立即丢弃它以获得下面form.save()的结果。更令人困惑的是,save行上的post = post.save()调用返回None,因为模型上的save方法无效。 (即现在post == None)我认为您可能需要重新考虑其中一些设计模式,以便以后为您节省一些痛苦。

编辑:在我提到的行上添加一些说明:

让我们隔离这些行:

1   if form.is_valid():
2      post = Post(image = request.FILES['image'])
3      post = form.save(commit=False)

在第2行,我们正在做的是创建一个新的Post模型实例,其图像等于我们从请求中获得的图像。到现在为止还挺好。但是为了将其提交到数据库,我仍然需要在.save()变量上调用post[source]

在第3行,对form.save(...)的调用返回一个新的Post模型实例(因为您指定了commit=False,因此也没有在数据库上)但请注意,您将post设置为等于结果。现在第2行的模型实例已经永远丢失了。

我不确定你是否希望第2行的行为方式如此,但如果你想以这种方式在数据库上制作某些东西,你可以写

Post(image = request.FILES['image']).save()

post = Post.objects.create(image = request.FILES['image'])

在第一个版本中,返回值为None,因为save是一个void函数。在第二种情况下,create方法实际上会返回已创建模型的实例,因此我建议您使用该实例。