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。如您所见,此函数仅捕获DoesNotExisttry / 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 次 |
| 最近记录: |