尝试通过表单创建Django模型实例,但我只想从表单中提取一些字段并手动设置其他字段

时间:2017-10-03 18:07:13

标签: python django forms

我正在尝试在Django中创建一个图库应用。我有两个模型:Pic和Profile,分别代表单个图片和用户配置文件。每个用户在注册网站时都会创建一个配置文件实例。以下是模型:

class Profile(models.Model):
    user = models.OneToOneField(User, related_name="profile")

class Pic(models.Model):
    profile = models.ForeignKey(Profile, blank=True, null=True)
    photo = models.ImageField(upload_to = "photos/%Y/%m/%d/")

我希望用户能够通过HTML表单上传图片。当他们上传图像时,我想创建一个ImageField对应于上传的Pic。我已经为Pic模型创建了一个ModelForm来实现这一目标。这是现在的形式:

class PicForm(forms.ModelForm):
    class Meta:
        model = Pic
        fields = ('photo',)

upload_image视图:

def upload_image(request):
    if request.method == "POST":
        form = PicForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            return redirect('home')
        else:
            return redirect('upload_image')
    else: 
        form = PicForm()
        return render(request, 'pics/upload_image.html', {
            'form': form
        }) 

问题是,我希望用户能够通过表单设置新Pic的照片字段,而不是配置文件字段。我希望将其设置为用户的个人资料。我怎么能做到这一点?

2 个答案:

答案 0 :(得分:2)

Bear Brown's answer是一种应该做到这一点的简单方法。但是,如果您要在多个位置使用相同的表单,它将会少dry。 (即使你目前的情况没有多少利润,但未来可能会给你带来更多的利润)因为这是一个经常被问到的问题,我会尝试多解释一下详细说明dry,谁知道它可能会让您或其他任何有相同问题的人受益。此外,将表单逻辑保留在form中通常是件好事。

因此,通过将user.profile方法或函数中的PicForm作为request.user传递给班级,可以获得view中的keyword argumentkwarg)和pop __init__中的user。然后,弹出的save可用于覆盖PicForm

中的data方法

BaseModelForm的前两个参数将您传递的filesrequest.POST作为request.FILESkwargs。要添加接受__init__的参数,您必须在接受PicForm的{​​{1}}中添加*args, **kwargs方法。

最终你将不得不应用Bear Brown提到的几乎相同的逻辑。您必须通过保存而不提交来从表单中获取数据。此时,您必须将用户的配置文件添加到Pic实例,最后在提交时实际保存它。

由于您设置了related_name,因此您可以通过self.user.profile从提交表单的用户处获取配置文件,因为我们通过弹出在self.user中定义了__init__来自user的{​​{1}}。

kwargs

如果您遇到上述情况,现在可以通过传递class PicForm(forms.ModelForm): class Meta: model = Pic fields = ('photo',) def __init__(self, *args, **kwargs): self.user = kwargs.pop('user') super(PicForm, self).__init__(*args, **kwargs) def save(self, commit=True): pic = super(PicForm, self).save(commit=False) pic.profile = self.user.profile if commit: pic.save() return pic request.POSTrequest.FILES来构建表单:

request.user

为什么这更适合面向未来,form = PicForm(request.POST, request.FILES, user=request.user) if form.is_valid(): form.save() 你可能会问?想象一下你自己在15个不同的位置使用dry,我可以用这样的形式想象。如果您想在保存时更改逻辑,例如根据PicForm,您必须在15个不同位置更改逻辑。在使用覆盖时,您可能只需要在一个位置更改它(当然不是总是

无论如何,选择适合你的。

答案 1 :(得分:1)

你可以尝试一下:

if form.is_valid():
    pic = form.save(commit=False)
    pic.profile = request.user.profile
    pic.save()
    return redirect('home')

form save method

的更多详细信息