我有两个简单的模型,一个代表电影,另一个代表电影的评分。
class Movie(models.Model):
id = models.AutoField(primary_key=True)
title = models.TextField()
class Rating(models.Model):
id = models.AutoField(primary_key=True)
movie = models.ForeignKey(Movie)
rating = models.FloatField()
我的期望是,我能够首先创建一个Movie
和一个Review
引用该电影的内容,然后将它们都提交到数据库中,只要我提交了Movie
第一个,以便为它提供一个主键以供Review
引用。
the_hobbit = Movie(title="The Hobbit")
my_rating = Rating(movie=the_hobbit, rating=8.5)
the_hobbit.save()
my_rating.save()
令我惊讶的是,它仍然IntegrityError
抱怨我试图指定一个空外键,即使Movie
已经提交并且现在有一个主键。
IntegrityError: null value in column "movie_id" violates not-null constraint
我通过添加一些print
语句来确认这一点:
print "the_hobbit.id =", the_hobbit.id # None
print "my_rating.movie.id =", my_rating.movie.id # None
print "my_rating.movie_id =", my_rating.movie_id # None
the_hobbit.save()
print "the_hobbit.id =", the_hobbit.id # 3
print "my_rating.movie.id =", my_rating.movie.id # 3
print "my_rating.movie_id =", my_rating.movie_id # None
my_rating.save() # raises IntegrityError
该.movie
属性指的是一个Movie
实例,它确实有一个非None
.id
-,但.movie_id
它保留了None
它在创建Movie
实例时所具有的值。
.movie.id
当我尝试提交时,我希望 Django 抬头Review
,但显然这不是它正在做的事情。
在旁边
就我而言,我通过在某些模型上覆盖该方法来处理此行为,.save()
以便它们在保存之前再次查找外键的主键。
def save(self, *a, **kw):
for field in self._meta.fields:
if isinstance(field, ForeignKey):
id_attname = field.attname
instance_attname = id_attname.rpartition("_id")[0]
instance = getattr(self, instance_attname)
instance_id = instance.pk
setattr(self, id_attname, instance_id)
return Model.save(self, *a, **kw)
这很 hacky,但它对我有用,所以我并不是真的在寻找解决这个特定问题的方法。
我正在寻找对 Django 行为的解释。Django 在什么时候查找外键的主键?请具体;最好参考 Django 源代码。