Bri*_*son 13 django python-2.7
我正在编写一个小的django命令来将数据从json API端点复制到Django数据库中.在我实际创建对象时obj, created = model.objects.get_or_create(**filters)
,我得到一个MultipleObjectsReturned
错误.这对我来说是令人惊讶的,因为我的理解get_or_create
是,如果我尝试创建一个已经存在的对象,它将只是"得到"它.
我不确定我正在克隆的数据库的完整性,但即使它中有多个相同的对象,当我将它们加载到我的本地Django数据库时,不应该get_or_create使它成为我永远不会超过一份?
任何人都能解释一下吗?我很乐意提供更多细节,我只是不想让读者陷入困境.
dno*_*zay 25
想象一下,你有以下模型:
class DictionaryEntry(models.Model):
name = models.CharField(max_length=255, null=False, blank=False)
definition = models.TextField(null=True, blank=False)
Run Code Online (Sandbox Code Playgroud)
和以下代码:
obj, created = DictionaryEntry.objects.get_or_create(
name='apple', definition='some kind of fruit')
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
现在假设您有一个带有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
Run Code Online (Sandbox Code Playgroud)
如果时间正确(或者错误取决于你想要如何表达这个),两个进程都可以进行查找而不能找到项目.他们都可以创建项目.一切都好...
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
Run Code Online (Sandbox Code Playgroud)
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'),)
Run Code Online (Sandbox Code Playgroud)
回到功能:
# 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
Run Code Online (Sandbox Code Playgroud)
假设你和以前有相同的种族,他们都没有找到该项目并继续插入; 这样做他们将开始交易,其中一个将赢得比赛,而另一个将看到一个IntegrityError
.
该示例使用a TextField
,用于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
用a 替换CharField
.CharField
可以在其中TextField
计算pre_save
并在其中使用的强哈希值unique_together
.顾名思义,get_or_create
model.objects.get()
s或model.objects.create()
s。
从概念上讲,它等效于:
try:
model.objects.get(pk=1)
except model.DoesNotExist:
model.objects.create(pk=1)
Run Code Online (Sandbox Code Playgroud)
来源是您找到这些类型问题的明确答案。提示:搜索def get_or_create
。如您所见,此函数仅捕获DoesNotExist
try / except。
def get_or_create(self, **kwargs):
"""
Looks up an object with the given kwargs, creating one if necessary.
Returns a tuple of (object, created), where created is a boolean
specifying whether an object was created.
"""
assert kwargs, \
'get_or_create() must be passed at least one keyword argument'
defaults = kwargs.pop('defaults', {})
lookup = kwargs.copy()
for f in self.model._meta.fields:
if f.attname in lookup:
lookup[f.name] = lookup.pop(f.attname)
try:
self._for_write = True
return self.get(**lookup), False
except self.model.DoesNotExist:
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
10014 次 |
最近记录: |