我有一个模型
class DeviceAdmin(models.Model):
dev_id = models.AutoField(db_column='dev_id', primary_key=True)
...
视图定位对象:
device = DeviceAdmin.objects.get(uuid=uuid)
然后它会做出一些改变(或者可能不会)
if (...):
device.os_type = 'windows'
...
然后它尝试保存任何更改:
device.save()
这里是Django尝试插入另一行而不是更新的地方,导致了一个DB错误
django.db.utils.IntegrityError: duplicate key value violates unique constraint
解决方案中有一种类似的问题:
一旦我将primary_key字段设置为自动字段,问题就消失了。
但是,我的主键已经是一个自动字段。
所以我用调试器逐步浏览了django代码,并在文件中资助了这个...站点包\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
似乎如果没有更改(因此更新不做任何事情),那么它将尝试插入重复记录。
我通过在< code>get之后添加一个保存来测试这一点:
device = DeviceAdmin.objects.get(uuid=uuid)
device.save()
它试图插入一个副本。
这是否意味着,我的代码需要跟踪一个对象是否必须保存到DB?
解决这个问题的最简单方法是什么?
更新:
作为一个测试,在用< code>get找到一个对象后,我立即执行< code>save,而不做任何更改:
device = DeviceAdmin.objects.get(uuid=uuid)
device.save()
Django应该知道这个对象是一个已经存在的对象。然而,它试图插入一个副本。
同样,创建一个新对象并调用保存
两次:
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!
第二次< code>save尝试插入一个副本——正如我可以看到的,如果我用调试器单步执行django代码。
可能发生这种情况的一个原因是如果您的主键字段使用默认值定义。我在您的示例中没有看到默认值,但我也没有看到数据类型是uuid,所以我想我会提供这个答案以防万一。
如果您的模型的pkey如下所示:models.UUIDField(primary_key=True,默认=uuid.uuid4)
,调用保存
将始终导致INSERT而不是UPDATE。我相信即使您将force_update=True
传递给保存方法,这也是真的。这曾经作为错误提交,但实际上是Django 3根据文档的预期行为。
如果要使用 uuid 作为主键,有几种方法可以解决此问题。最好的方法可能是遵循文档的建议,并使用更新或update_or_create方法来更新模型实例。
>>> MyModel.objects.update_or_create(pk=existing_pk, defaults={'name': 'new name'})
>>> MyModel.objects.filter(pk=existing_pk).update(name='new name')
或者,您也可以从主键定义中删除默认参数,并通过覆盖模型的save方法来确保每个实例在保存时都有一个分配的uuid例如:
def save(self, *args, **kwargs):
if not self.id:
self.id = uuid.uuid1()
super(DeviceAdmin, self).save(*args, **kwargs)
在我的例子中,我在班上有一个独特的CharField。在我看来,Django有时会将它视为主键,有时不会——结果是有时没有意识到它应该是更新而不是插入。
添加显式的id=AutoField(primary_key=True)
为我解决了问题。
您在字段定义方面肯定有一些问题(可能出于某种原因,您应该添加< code>unique=True)。但是如果您仍然不能确定更新失败的原因(如果< code>UPDATE返回“no rows updated”,则发生< code>INSERT),那么您可以使用< code >。保存(force_update=True)作为最后的手段。
此外,您的代码中存在一些不一致:
dev_id
但您在筛选中使用 uuid
(.get(uuid=uuid)
)。是否确实为primary_key字段设置了名称?AutoField
假设使用整数
字段,因此在get_prep_value
期间,它会执行int(self.pk),
其工作而不会在uuid实例上抛出任何错误。UUID
,但如果 db 内部使用 varchar
字段,则它将被转换回具有错误值的 str(例如 str(int(uuid.UUID('579aea21-49a4-4819-90ec-a192014b4a44')) == “116447198070669671892400511866020514372”
)。所以这就是可能导致问题的原因。尝试使用 UUID
字段或字符字段,而不是自动字段
:import uuid
class SomeModel(models.Model):
dev_id = models.UUIDField(primary_key=True, blank=True, default=uuid.uuid4)
# Or if your column is a varchar:
class SomeModel(models.Model):
def dev_id_default():
return uuid.uuid4().hex # or str(uuid.uuid4()) if you need values with `-`
dev_id = models.CharField(primary_key=True, blank=True, default=dev_id_default, max_length=33_OR_36)
看起来您正在使用数据库中预先存在的表:尝试使用python manage.py inspectdb
生成的模型的代码。
嗨,我是Spring Data JPA的新手,我想知道即使我将Id传递给实体,Spring data jpa也是插入而不是合并的。我想当我实现持久接口并实现这两个方法时: 它将自动合并而不是持久化。 我有一个名为User like的实体类: 再上一节课 我有一个名为UserRepostory的自定义存储库,它扩展了JpaReopistory。当我看到实现演示SpringDataJpa使用以上两种方
问题内容: 我有一个简单的测试,尝试在其中更新对象,但是合并似乎在执行插入操作而不是更新操作。 } 这是我的更新方法 更新代码 现在,我收到以下错误无法提交JPA事务;嵌套的异常是javax.persistence.RollbackException:标记为rollbackOnly的事务 问题答案: 我有一个版本列,当种子数据插入数据库时未设置该列。因此,所有有关更新和删除的问题
问题内容: 编辑。在扩展基本存储库类并添加insert方法的同时,一个更优雅的解决方案似乎是在实体中实现Persistable。查看 可能的解决方案2 我正在使用Hibernate作为ORM 创建服务。 遵循本教程的基础。 http://www.petrikainulainen.net/spring-data-jpa- tutorial/ 我的实体存储库扩展 我正在使用使用有意义的主键而不是自动生
当试图更新现有的Django模型对象时(使用< code>save()方法),会插入一个新行。 例如: 在第二次调用< code>save()方法之后,一个重复的条目被插入到我的表中。 以下是模型定义的示例:
Spring Boot 2.4.0,DB是MySql 8。 使用REST每15秒从远程获取数据并使用将其存储到MySql DB。 它为所有给定的实体调用save()方法。 所有数据都设置了ID。 我希望如果DB中没有这样的id-它将被插入。 如果这样的ID已经在DB中呈现-它将被更新。 这里是从控制台剪下的: 下面是获取和保存的方法,如下所示: 此方法每15秒运行一次。 实体: 和存储库: 这是以
我有一个地址对象,它具有城市属性。创建要通过EF6插入的全新地址时,我会填写所有必需的基本地址属性(地址行1、邮政编码等),但我不需要完全水合的城市实例,只要它具有如下ID: 当我尝试插入我的地址时,它也会尝试对城市的属性进行验证,但我不想对城市进行任何CRUD,因为我只需要它的ID。 我发现了下面的问题,它引导我从DbContext中分离条目,这样EF就不会试图对所述对象执行CRUD: 如何阻止