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

2020-02-14 11:55:21 +08:00
 wuming

在 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 的行已经存在,但是都能够正常保存。请问我在哪里理解错误了?又是什么情况才会触发文档中的错误。

1649 次点击
所在节点    问与答
6 条回复
vicalloy
2020-02-14 12:51:19 +08:00
你没有看清楚,“force_insert=True”的时候才会强制插入导致报错。
wuming
2020-02-14 13:30:39 +08:00
@vicalloy 这上面不是说的是当提供主键时,相当于给 model.save() 传递 force_insert =True 么。也就是不需要我主动传递 force_insert
hzwjz
2020-02-14 13:32:05 +08:00
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
2020-02-14 13:48:36 +08:00
@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
2020-02-14 15:58:01 +08:00
我的理解, "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
2020-02-14 16:26:52 +08:00
@qqxx520 感谢

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/644499

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX