サンプルコード
次のモデルがあるとします。
class DictionaryEntry(models.Model):
name = models.CharField(max_length=255, null=False, blank=False)
definition = models.TextField(null=True, blank=False)
および次のコード:
obj, created = DictionaryEntry.objects.get_or_create(
name='apple', definition='some kind of fruit')
get_or_create
のコードをget_or_create
見たことがない場合:
# simplified
def get_or_create(cls, **kwargs):
try:
instance, created = cls.get(**kwargs), False
except cls.DoesNotExist:
instance, created = cls.create(**kwargs), True
return instance, created
ウェブサーバーについて...
2
ここで、両方のワーカー プロセスが同時にデータベースにアクセスできるWeb サーバーがあるとします。
# simplified
def get_or_create(cls, **kwargs):
try:
instance, created = cls.get(**kwargs), False # <===== nope not there...
except cls.DoesNotExist:
instance, created = cls.create(**kwargs), True
return instance, created
タイミングが正しければ (言い方によっては間違っても)、両方のプロセスで検索が行われ、アイテムが見つからない可能性があります。両方がアイテムを作成する場合があります。すべて順調...
MultipleObjectsReturned: get() returned more than one KeyValue -- it returned 2!
すべてが順調です... 3 回目に電話get_or_create
するまでは、「3 回目は魅力的です」と彼らは言います。
# simplified
def get_or_create(cls, **kwargs):
try:
instance, created = cls.get(**kwargs), False # <==== kaboom, 2 objects.
except cls.DoesNotExist:
instance, created = cls.create(**kwargs), True
return instance, created
unique_together
どうすればこれを解決できますか?おそらく、データベース レベルで制約を適用します。
class DictionaryEntry(models.Model):
name = models.CharField(max_length=255, null=False, blank=False)
definition = models.TextField(null=True, blank=False)
class Meta:
unique_together = (('name', 'definition'),)
関数に戻ります。
# simplified
def get_or_create(cls, **kwargs):
try:
instance, created = cls.get(**kwargs), False
except cls.DoesNotExist:
instance, created = cls.create(**kwargs), True # <==== this handles IntegrityError
return instance, created
あなたが以前と同じ人種を持っていて、どちらもアイテムを見つけられず、挿入に進んだとします。そうすることで、彼らはトランザクションを開始し、そのうちの 1 人がレースに勝ち、もう 1 人はIntegrityError
.
mysql ?
この例では、 (私の場合)に変換される aTextField
を使用しています。制約を追加すると、 .mysql
LONGTEXT
unique_together
syncdb
django.db.utils.InternalError: (1170, u"BLOB/TEXT column 'definition' used in key specification without a key length")
MultipleObjectsReturned
そのため、手動で処理する必要がある場合があります。
可能な解決策
- を に置き換えることができる場合があり
TextField
ますCharField
。
- で計算して使用できる
CharField
の強力なハッシュであるを追加することも可能です。TextField
pre_save
unique_together