Django NOT NULL约束失败userprofile.user_在上载fi时的id

2024-06-11 02:55:26 发布

您现在位置:Python中文网/ 问答频道 /正文

我是Django的新手,尝试实践一个简单的项目,用户注册(使用Django registration redux),上传一些文件,然后s/he会得到一个她的文件列表,可以下载。下面分别是my models.py、forms.py和视图:

型号.py

class UserProfile(models.Model):
    user = models.ForeignKey(User, related_name='uploaded_by')
    names = models.CharField(max_length=40)
    lastname = models.CharField(max_length=50)
    email = models.EmailField()
    uploads = models.FileField(upload_to= 'blablabla')

    def __str__(self):
        return self.email

表单.py

class UserProfileForm(forms.ModelForm):
    class Meta:
        model = UserProfile
        fields = ['names', 'uploads']

查看.py

from .forms import UserProfileForm
from .models import UserProfile
@login_required()
def new(requst):
    form = UserProfileForm(requst.POST or None, requst.FILES or None)
    if form.is_valid():
        form.save()
    context = {'title': 'welcome', 'form': form}
    return render(requst, 'upform.html', context)

但是,当我使用用户登录并尝试上载文件时,我会得到错误:IntegrityError at/new 非空约束失败:_userprofile.user_id

在深入研究之后,我注意到有人建议错误的原因是因为用户在发布表单的过程中无论如何都不包括在内,所以我尝试了我想到的任何方法,并在表单中添加了用户字段。py成功了:

表单.py

class UserProfileForm(forms.ModelForm):
    class Meta:
        model = UserProfile
        fields = ['names', 'uploads']

但问题是浏览器中显示的表单现在包含一个包含所有注册用户的下拉列表。我一直看到不同的错误,试图将登录用户与视图中的表单关联起来。 我的问题是:如何以透明的方式将上传与登录用户关联起来。 抱歉,如果这个问题太新了


Tags: 文件django用户pyform表单namesmodels
3条回答

将用户保留在表单之外并在保存时添加:

if form.is_valid():
    profile = form.save(commit=False)
    profile.user = request.user
    profile.save()

我必须说你的模型看起来有点奇怪;你为每个用户有多个配置文件,每个都有一个上传。似乎你更希望一个单一的配置文件,与用户的一个单一的关系,而不是一个单独的上传模型与用户配置文件的外键。

I added the user field to the forms.py worked:

这可能还会打开一个安全漏洞,因为您可以从应用程序外部设置用户,从而覆盖已登录的用户。

After digging a lot I noticed someone suggested the reason of the error is because the user is not included anyhow in the process of posting the form.

你想得很对。如果用户不是字段,则表单永远不知道如何填充UserProfileuser字段。由于没有填充的user外键就无法保存UserProfile,因此会出现错误。

有多种方法可以解决这个问题:

解决此问题的一种方法是在表单上使用^{},将用户修补到未保存的实例中,然后手动将对象保存到数据库:

if form.is_valid():
    profile = form.save(commit=False)
    profile.user = requst.user
    profile.save()

这稍微违反了封装,因为您现在处理表单外部的数据库保存。

您还可以为表单提供初始“模板”实例:

form = UserProfileForm(
   requst.POST,
   requst.FILES,
   instance=UserProfile(user=self.request.user)
)

无论如何,您可能希望这样做,因为表单还允许编辑现有的用户配置文件。目前,您每次都要保存一个新的UserProfile,并且由于user不是模型类中的unique=True,因此您将为每个用户获得多个配置文件。 如果您不希望这样做,请检查Daniel Roseman的答案,因为您可能希望UserProfile.user成为^{}字段。

在这种情况下,我们可以简化为

profile, created = UserProfile.objects.get_or_create(user=request.user)
form = UserProfileForm(
    requst.POST,
    requst.FILES,
    instance=profile
)

还要注意,我删除了or None,因为这是不必要的。BaseForm(它是ModelForm派生的)为您执行此检查(它实际上执行self.data = data or {}),这实际上撤消了先前的无通知)

你可以听从丹尼尔的建议。

class UserProfile(models.Model):
  user = models.OneToOneField(User, related_name='uploaded_by')
  names = models.CharField(max_length=40)
  lastname = models.CharField(max_length=50)
  email = models.EmailField()


class UserFiles(models.Model):
  user = models.ForeignKey(UserProfile)
  file = models.FileField(upload_to= 'blablabla')

记住OneToOneField类似于具有unique=True属性的ForeignKey。

相关问题 更多 >