我正在尝试制作一个允许用户上传文件(纯文本字典文件)的表单。这是我的模特:
from django.conf import settings
from django.db import models
import uuid
class Dictionary(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
owner = models.ForeignKey(settings.AUTH_USER_MODEL)
file = models.FileField(upload_to='uploads/%y/%m/%d')
timestamp = models.DateTimeField(auto_now_add=True)
这是我用它的表格。我想只公开要设置的用户的文件参数。我打算从请求用户设置的所有者:
from django.forms import ModelForm
from dic.models import Dictionary
class DictionaryForm(ModelForm):
class Meta:
model = Dictionary
fields = ['file']
def __init__(self, owner, *args, **kwargs):
self.owner = owner
super().__init__(*args, **kwargs)
这是我的视图代码,它将发布数据,文件和用户发送到表单:
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render
from dic.forms import DictionaryForm
@login_required
def upload(request):
if request.method == 'POST':
form = DictionaryForm(request.user, request.POST, request.FILES)
if form.is_valid():
form.save()
return HttpResponseRedirect('/dic/upload_success')
else:
form = DictionaryForm(request.user)
return render(request, 'dic/upload.html', {'form': form})
这是我失败的测试代码:
def test_can_upload_file(self):
user = User.objects.create(username='foo')
user.save()
self.client.force_login(user)
self.assertEqual(Dictionary.objects.count(), 0)
file = StringIO(initial_value='fake data here')
response = self.client.post('/dic/upload', {'file':file})
self.assertEqual(response.status_code, 200)
断言行永远不会运行,因为首先发生错误。生成的错误位于form.save()
的视图代码中。生成的错误是:
django.db.utils.IntegrityError: NOT NULL constraint failed: dic_dictionary.owner_id
两个问题。如何在表单中正确设置所有者值,以便不会发生此错误?为什么错误发生在form.save()
行,因为is_valid()
应该检查不会发生错误?
答案 0 :(得分:3)
is_valid()
仅验证您在表单中指定的字段(在本例中为file
)。表单有效 - 但稍后会出现错误,因为保存时不满足其他模型字段约束。
将owner
传递给表单不起作用,因为表单不处理该字段。相反,您需要在表单验证后将owner
添加到模型中,但在保存之前:
if request.method == 'POST':
form = DictionaryForm(request.POST, request.FILES)
if form.is_valid():
obj = form.save(commit=False)
obj.owner = request.user
obj.save()
return HttpResponseRedirect('/dic/upload_success')
(同时删除表单上的__init__
方法)。