示例代码
假设您有以下模型:
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
工作进程的网络服务器,它们都有自己的数据库并发访问权限。
# 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!
一切都很好......直到你get_or_create
第三次打电话,他们说“第三次是一种魅力”。
# 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
假设你和之前有相同的种族,他们都没有找到该项目并继续插入;这样做他们将开始一个事务,其中一个将赢得比赛,而另一个将看到IntegrityError
.
mysql?
该示例使用 a TextField
,用于mysql
转换为 a 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
。
- 可以添加 a
CharField
,它可能是 的强散列TextField
,您可以pre_save
在 a 中计算和使用unique_together
。