我正在尝试在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的照片字段,而不是配置文件字段。我希望将其设置为用户的个人资料。我怎么能做到这一点?
答案 0 :(得分:2)
Bear Brown's answer是一种应该做到这一点的简单方法。但是,如果您要在多个位置使用相同的表单,它将会少dry
。 (即使你目前的情况没有多少利润,但未来可能会给你带来更多的利润)因为这是一个经常被问到的问题,我会尝试多解释一下详细说明dry
,谁知道它可能会让您或其他任何有相同问题的人受益。此外,将表单逻辑保留在form
中通常是件好事。
因此,通过将user.profile
方法或函数中的PicForm
作为request.user
传递给班级,可以获得view
中的keyword argument
(kwarg
)和pop
__init__
中的user
。然后,弹出的save
可用于覆盖PicForm
data
方法
BaseModelForm
的前两个参数将您传递的files
和request.POST
作为request.FILES
和kwargs
。要添加接受__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.POST
和request.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')
的更多详细信息