2 つの単純なモデルがあります。1 つは映画を表し、もう 1 つは映画の評価を表します。
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
、null の外部キーを指定しようとしているという不満がまだ出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)
これはハッキーですが、私にとってはうまくいくので、この特定の問題の解決策を実際に探しているわけではありません。
Django の動作の説明を探しています。Django はどの時点で外部キーの主キーを検索しますか? 具体的にお願いします。Django ソース コードへの参照が最適です。