wuming
V2EX  ›  问与答

Django 3.0 中的 model.save() 行为问题

By wuming at 2020 年 2 月 14 日 · 2990 次点击

在 release note 中写的是

Model.save() no longer attempts to find a row when saving a new Model instance and a default value for the primary key is provided, and always performs a single INSERT query. 

This makes calling Model.save() while providing a default primary key value equivalent to passing force_insert=True to model’s save(). Attempts to use a new Model instance to update an existing row will result in an IntegrityError.

In order to update an existing model for a specific primary key value, use the update_or_create() method or QuerySet.filter(pk=…).update(…) instead. 

貌似是 model 中有 id 时,只会执行插入而不会更新,从而可能触发 IntegrityError。

但是我在测试的时候发现

Class Order(models.Model):
    status = models.PositiveSmallIntegerField(default=1)

order = Order.objects.filter(id=1).first()
order.status = 2
order.save()

或者

order = Order()
order.id =1
order.status=2
order.save()

这里 id=1 的行已经存在,但是都能够正常保存。请问我在哪里理解错误了?又是什么情况才会触发文档中的错误。

6 条回复  •  2020-02-14 16:26:52 +08:00
vicalloy
   1
vicalloy  
   2020 年 2 月 14 日
你没有看清楚,“force_insert=True”的时候才会强制插入导致报错。
wuming
   2
wuming  
OP
   2020 年 2 月 14 日
@vicalloy 这上面不是说的是当提供主键时,相当于给 model.save() 传递 force_insert =True 么。也就是不需要我主动传递 force_insert
hzwjz
   3
hzwjz  
   2020 年 2 月 14 日 via Android
Attempts to use a new Model instance to update an existing row will result in an IntegrityError.


old_order 已存在的情况下且 id 我假设为 1,然后
new_order = Order()
new_order.id = 1
new_order.save(). # IntegrityError
wuming
   4
wuming  
OP
   2020 年 2 月 14 日
@hzwjz 刚才这样做了,还是没有任何错误。

old_order = Order.objects.get(id=1)
print(old_order.id) #执行完之后看到的 id=1
new_order = Order()
new_order.id = 1
new_order.save() #执行完之后没有任何错误。
qqxx520
   5
qqxx520  
   2020 年 2 月 14 日   ❤️ 1
我的理解, "Default value for primary key is provided"意思是在 model 建立时的主键字段有 default=xxx, 例如
Class Order(models.Model):
id=models.AutoField('ID', primary_key=True, auto_created=True, default=True)
status = models.PositiveSmallIntegerField(default=1)

测试代码:
>>> a=Order()
>>> a.save()
>>> a
<Order: Order object (1)>
>>> a.id
1
>>> b=Order()
>>> b.save()
Traceback (most recent call last):
...
sqlite3.IntegrityError: UNIQUE constraint failed: order_order.id
>>> b.id=2
>>> b.save()
>>> a,b
(<Order: Order object (1)>, <Order: Order object (2)>)

但是 id 字段的 default value 是 True,似乎没什么意思,可以改进为如下的定义:
import time
from django.db import models

def get_pk():
return int(time.time() * 10000)

class Order(models.Model):
id=models.AutoField('ID', primary_key=True, auto_created=True, default=get_pk)
status = models.PositiveSmallIntegerField(default=1)

测试代码:
>>> c=Order()
>>> c.save()
>>> c.id
15816669672836
>>> d=Order()
>>> d.save()
>>> d.id
15816669758912

-- 完毕 --
wuming
   6
wuming  
OP
   2020 年 2 月 14 日
@qqxx520 感谢
© 2026 V2EX · 34ms · 3.9.8.5