IntegrityError at ** NOT NULL constraint failed: learning_logs_topic.owner_id
最近在学习《python 从入门到实战》第19章,在learning_logs中models 添加了topic的用户属性,即哪个用户登录后创建的topic,则此topic的owner属性为此登录用户,代码:owner=models.ForeignKey(User,on_delete=models.CASCADE),owner 是User的外键(pthon 版本3.7.4,django版本2.2.6 ),并且在makemigrations后出现了如下提示:
此时选择是‘1)’的选项,然后选择的用户ID为1,即ll_admin,此时即原有topic的归属用户ID为1,即ll_admin,在执行new_topic时出现了如下错误:
IntegrityError at /new_topic/ NOT NULL constraint failed: learning_logs_topic.owner_id,错误现场如下:
其中topic 的model 源码如下:
class Topic(models.Model) :
text=models.CharField(max_length=200)
date_added=models.DateTimeField(auto_now_add=True)
owner=models.ForeignKey(User,on_delete=models.CASCADE)
def __str__(self) :
return self.text
topicform的源码如下:
class TopicForm(forms.ModelForm):
class Meta :
model=Topic
fields =['text']
labels={'text' : ''}
learning_logs 文件夹下views.py 的new_topic 源码如下:
def new_topic(request) :
if request.method != 'POST' :
form=TopicForm()
else :
form= TopicForm(request.POST)
if form.is_valid() :
form.save()
return HttpResponseRedirect(reverse('learning_logs:topics'))
context={'form':form}
return render(request,'learning_logs/new_topic.html',context)
此错误显示空值限制错误:owner,owner是models里面刚添加的属性,虽然在已存在的topic添加了owner 属性,但新添加的topic没有owner属性,所以报错。
解决的过程如下:
(1)在models.py 属性添加null=True,即允许此属性为空
修改后变为owner=models.ForeignKey(User,on_delete=models.CASCADE,null=True),修改后错误不再出现,但新添加的topic的owner为NULL,非设计所愿
(2)在models.py 里面添加默认值。
修改后owner=models.ForeignKey(User,on_delete=models.CASCADE,default=1),修改后错误也不再出现,但新添加的topic的owner均为ID为1的用户,也非设计所愿
(3)修改TopicForm,添加owner 字段
修改后TopicForm 变为如下:
class TopicForm(forms.ModelForm):
class Meta :
model=Topic
fields =['text,‘owner’']
labels={'text' : '','owner':''}
修改后将由用户选择此新建topic 的owner,如下所示:
虽然可以选择当前登录用户为此topic的owner ,但用户也可以选择其它非当前登录用户,增加了出现错误的风险
(4)在views.py new_topic视图里,用request.user 获取当前用户,并赋值给form
即在if form.is_valid() :后添加一行:
form.instance.owner=request.user,修改后变为:
def new_topic(request) :
if request.method != 'POST' :
form=TopicForm()
else :
form= TopicForm(request.POST)
if form.is_valid() :
form.instance.owner=request.user
form.save()
return HttpResponseRedirect(reverse('learning_logs:topics'))
context={'form':form}
return render(request,'learning_logs/new_topic.html',context)
即用Form的instance 参数,来获取owner 属性,并用requset.user得到的当前用户赋值给此instance的owner。修改后程序实现预定功能
(5)也是利用了instance参数,不过是在生成的Form的时候,修改后new_topic的视图如下:
def new_topic(request) :
if request.method != 'POST' :
form=TopicForm()
else :
form= TopicForm(request.POST)
topic=Topic()
topic.owner=request.user
form= TopicForm(request.POST,instance=topic)
if form.is_valid() :
form.save()
return HttpResponseRedirect(reverse('learning_logs:topics'))
context={'form':form}
return render(request,'learning_logs/new_topic.html',context)
先生成一个topic,然后赋值给owner,再将此topic赋值给instance参数,空间、时间成本较大,不过也实现了预定的功能。