Django尝试在save()上插入而不是更新
我有一个模型Django尝试在save()上插入而不是更新,django,django-models,Django,Django Models,我有一个模型 class DeviceAdmin(models.Model): dev_id = models.AutoField(db_column='dev_id', primary_key=True) ... 视图可定位对象: device = DeviceAdmin.objects.get(uuid=uuid) 然后它会做出一些改变(或者可能不会) 然后尝试保存任何更改: device.save() device = DeviceAdmin.objects.get(uuid
class DeviceAdmin(models.Model):
dev_id = models.AutoField(db_column='dev_id', primary_key=True)
...
视图可定位对象:
device = DeviceAdmin.objects.get(uuid=uuid)
然后它会做出一些改变(或者可能不会)
然后尝试保存任何更改:
device.save()
device = DeviceAdmin.objects.get(uuid=uuid)
device.save()
这里是Django尝试插入另一行而不是更新的地方,导致DB错误
django.db.utils.IntegrityError: duplicate key value violates unique constraint
有一种类似的解决方案:
一旦我将主键字段设置为自动字段,问题就消失了
但是,我的主键已经是一个自动字段
因此,我使用调试器逐步完成了django代码,并在文件…site packages\django\models\base.py
中为其提供资金:
# If possible, try an UPDATE. If that doesn't update anything, do an INSERT.
if pk_set and not force_insert:
base_qs = cls._base_manager.using(using)
values = [(f, None, (getattr(self, f.attname) if raw else f.pre_save(self, False)))
for f in non_pks]
forced_update = update_fields or force_update
updated = self._do_update(base_qs, using, pk_val, values, update_fields,
forced_update)
if force_update and not updated:
raise DatabaseError("Forced update did not affect any rows.")
if update_fields and not updated:
raise DatabaseError("Save with update_fields did not affect any rows.")
if not updated:
if meta.order_with_respect_to:
# If this is a model with an order_with_respect_to
# autopopulate the _order field
field = meta.order_with_respect_to
filter_args = field.get_filter_kwargs_for_object(self)
order_value = cls._base_manager.using(using).filter(**filter_args).count()
self._order = order_value
fields = meta.local_concrete_fields
if not pk_set:
fields = [f for f in fields if f is not meta.auto_field]
update_pk = meta.auto_field and not pk_set
result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
if update_pk:
setattr(self, meta.pk.attname, result)
return updated
看起来,如果没有任何更改(因此更新不起任何作用),那么它将尝试插入一条重复的记录
我通过在get
之后添加一个save来测试这一点:
device = DeviceAdmin.objects.get(uuid=uuid)
device.save()
它正试图插入一个副本
这是否意味着,我的代码需要跟踪对象是否必须保存到DB
解决这个问题最简单的方法是什么
更新: 作为测试,我在找到带有
get
的对象后立即进行save
,没有任何更改:
device.save()
device = DeviceAdmin.objects.get(uuid=uuid)
device.save()
Django应该知道该对象是一个现有对象。然而,它试图插入一个副本
同样,创建一个新对象并调用save
两次:
device = DeviceAdmin(...) # create a new object (it has null `dev_id`)
device.save() # insert the new object into DB; get 'dev_id'
# for the newly inserted record
device.save() # This shouldn't do anything!
第二次
保存
尝试插入一个副本-我可以看到,如果我使用调试器单步执行django代码。您肯定在字段定义方面有一些问题(可能出于某种原因,您应该添加unique=True
)。但是,如果您仍然无法确定更新失败的原因(INSERT
如果UPDATE
返回“未更新行”),那么您可以使用.save(force\u UPDATE=True)
作为最后手段
您的代码中也存在一些不一致之处:
- 字段名为
,但您正在筛选中使用dev\u id
(uuid
)。是否确定已正确设置主键字段的名称李>.get(uuid=uuid)
假设使用AutoField
字段,因此在Integer
期间,它会执行get_prep_value
操作,不会在int(self.pk)
实例上抛出任何错误,但如果db内部使用uuid.uuid
字段,则会将其转换回具有错误值的str(例如,varchar
),这就是问题的原因。请尝试使用str(int(uuid.uuid('579aea21-49a4-4819-90ec-a192014b4a44'))=='1164471980706669671892400511866020514372'
或UUIDField
):CharField
导入uuid
类模型(models.Model):
dev_id=models.UUIDField(主键=True,空白=True,默认=uuid.uuid4)
#或者,如果您的列是varchar:
类模型(models.Model):
def dev_id_default():
如果需要具有以下参数的值,请返回uuid.uuid4().hex#或str(uuid.uuid4())`-`
dev\u id=models.CharField(主键=True,空格=True,默认值=dev\u id\u默认值,最大长度=33\u或36)
看起来您正在使用DB中预先存在的表:尝试为生成的模型使用代码。在我的例子中,我的类的顶部有一个唯一的CharField。在我看来,Django有时会将其视为主键,有时则不会——其结果是有时没有意识到它应该更新而不是插入
添加一个显式的
id=AutoField(primary\u key=True)
为我解决了这个问题。你的序列有没有搞乱?你试过这种方法吗(尽管我不确定它是否能解决):device.save(update\u fields=['field'])
或者你可以使用device=DeviceAdmin.objects.filter(uuid=uuid.update(field=value)
序列很好。我检查过了。您的诊断不正确。更新的
标志只有在没有行匹配的情况下才会为假,即PK不存在。如果PK存在,则不会为假,但值设置为与现在相同。从您的另一个问题中,我知道您在数据库中已经有表了。您能显示什么吗如果您为您的模型使用由manage.py inspectdb
生成的代码,并且您可以始终退回到为.save使用.save(force\u update=True)
for.save(force\u update=True),如果DB返回无更改,它仍将覆盖它,还是不会在幕后采取任何操作。