Django笔记十八之save函数的继承操作和指定字段更新等实例方法
本文首发于微信公众号:Hunter后端
这篇笔记主要介绍 Django 一些实例方法。
什么是 实例,我们知道通过filter() 的一些筛选方法,得到的是 QuerySet,而 QuerySet 取单条数据,通过索引,或者 first() 或者 last() 等方法,得到的单条数据,就是一个 model 的实例。
我们接下来要介绍的就是这种单条实例的一些方法。
- save() 的继承操作
- refresh from db, 从数据库中更新实例数据
- 自增的主键
- 指定字段更新 save()
1、save() 的继承操作
对于一个 model,我们可以通过 save() 的方式创建一条数据,比如:
from blog.models import Blog
blog = Blog(name="blog_1", tagline="tagline_1")
blog.save()
对于上面的 blog,我们就称其为 Blog 的一个实例。
我们可以通过继承覆盖原有的 save() 方法,然后新增一些我们需要的操作,比如打印日志,发送提醒等。
方法如下:
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
def save(self, *args, **kwargs):
print("save")
super(Blog, self).save(*args, **kwargs)
这样,我们在对 Blog 数据进行 save() 操作的时候,就可以看到控制台会输出 "save" 的记录。
除此之外,Django 的文档提出了一种方式,在 model 中定义一个类方法,可以方便我们对数据进行处理:
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
@classmethod
def create(cls, name, tagline):
blog = cls(name=name, tagline=tagline)
print("get an unsaved Blog instance")
return blog
然后通过调用该方法,传入参数,可以得到一个未保存的实例:
from blog.models import Blog
blog = Blog.create(name='test_create', tagline='test_tagline')
blog.save()
注意: 在我们执行 create() 方法的时候,程序还没有操作数据库,只是得到一个未保存的实例,我们仍然需要执行 save() 操作才能保存到数据库。
除了这种方法,还有一种官方文档更推荐的方法,就是使用 manager,这个的用法我们在后面几篇笔记中涉及,这里只做一个展示:
class BlogManager(models.Manager):
def create_blog(self, name, tagline):
blog = self.create(name=name, tagline=tagline)
# do something with the blog
print("get an unsaved Blog instance")
return blog
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
objects = BlogManager()
需要注意的是,这里调用的是 create() 方法,所以直接保存到了数据库,不用再执行 save() 方法了。
2、refresh from db, 从数据库中更新实例数据
方法为 refresh_from_db()
作用为从数据库中获取实例数据的最新值。
blog = Blog.objects.first()
# 其他地方可能会对 blog 数据进行一些更改
# 然后从数据库中拉取 blog 的最新数据
blog.refresh_from_db()
这个操作我个人常常用在写单元测试,比如经过一系列操作之后,想要查看这个 obj 的数据有没有更改,这种情况下就可以使用这个函数。
说一下 refresh_from_db() 这个函数的性能问题,refresh_from_db() 的底层函数也是使用的 get() 方法
所以使用 refresh_from_db() 和 get(pk=xx) 这两者在性能上可能差别不会很大,但是 refresh_from_db() 则更为简洁。
3、自增的主键
如果我们没有为 model 设置 PrimaryKey,那么系统则会自动为 model 设置自增主键为 id 的字段,创建数据的时候,不指定该字段,系统会自动为其赋值。
而当我们想要复制一条数据记录的时候,我们可以将 id 字段置为 None,然后 save(),系统则会将其视为一条新数据,从而自动保存为新数据并为 id 字段赋值。
b = Blog.objects.first()
b.id = None
b.save()
b.id
4、指定字段更新 save()
假设有一个 TestModel,有一个 number 字段,我们想要对其执行 +1 的操作,大概行为可能如下:
obj = TestModel.objects.get(id=1)
obj.number += 1
obj.save()
我们也可以通过 F() 函数这种稍微快一点和避免竞争的方式(竞争的意思是,其他的进程可能也在使用这条数据):
from django.db.models import F
obj = TestModel.objects.get(id=1)
obj.number = F('number') + 1
obj.save()
指定字段保存
单纯的使用 save() 操作可能会造成一个问题,比如说,我们在某一个 get 了一条数据,对 name 字段进行了更改,但同时另一个进程对同一条数据也进行了更改,我们对这条数据进行 save() 操作,那么就可能造成数据不一致的情况。
blog = Blog.objects.get(id=1)
blog.name = "test_1"
# 在这个期间,另一个进程对 tagline 字段进行了更改
# 假设该操作为 Blog.objects.filter(id=1).update(tagline="new_tagline")
# 然后执行 save() 操作
blog.save()
那么这个时候,blog 的数据因为已经从数据库中获取了出来,再执行 save() 则会保存之前获取的数据,这样会导致在此期间对 tagline 字段进行的更新操作还原。
那么这个时候,为了避免这种情况发生,我们在 save() 的时候指定我们要更新的字段来保存数据:
blog.name = "test_1"
blog.save(update_fields=["name"])
以上就是本篇笔记全部内容,下一篇笔记将介绍 manager 的用法。
如果想获取更多相关文章,可扫码关注阅读:

Django笔记十八之save函数的继承操作和指定字段更新等实例方法的更多相关文章
- python3.4学习笔记(十八) pycharm 安装使用、注册码、显示行号和字体大小等常用设置
python3.4学习笔记(十八) pycharm 安装使用.注册码.显示行号和字体大小等常用设置Download JetBrains Python IDE :: PyCharmhttp://www. ...
- (C/C++学习笔记) 十八. 继承和多态
十八. 继承和多态 ● 继承的概念 继承(inheritance): 以旧类为基础创建新类, 新类包含了旧类的数据成员和成员函数(除了构造函数和析构函数), 并且可以派生类中定义新成员. 形式: cl ...
- python 学习笔记十八 django深入学习三 分页,自定义标签,权限机制
django Pagination(分页) django 自带的分页功能非常强大,我们来看一个简单的练习示例: #导入Paginator>>> from django.core.p ...
- Opencv笔记(十八)——轮廓的更多函数及其层次结构
凸缺陷 前面我们已经学习了轮廓的凸包,对象上的任何凹陷都被成为凸缺陷.OpenCV 中有一个函数 cv.convexityDefect() 可以帮助我们找到凸缺陷.函数调用如下: hull = cv2 ...
- Django(十八)Model操作补充
参考博客:http://www.cnblogs.com/wupeiqi/articles/6216618.html 1. 创建类 class UserInfo(model.Model): age = ...
- 嵌入式Linux驱动笔记(十八)------浅析V4L2框架之ioctl【转】
转自:https://blog.csdn.net/Guet_Kite/article/details/78574781 权声明:本文为 风筝 博主原创文章,未经博主允许不得转载!!!!!!谢谢合作 h ...
- django 笔记8 url模板 自定义函数 simple_tag
感谢alex老师~ 知识点: URL - 两个没见 url>路由系统> 函数或类 > 返回字符串 Form表单提交: 提交 >url>函数或类中的方法 -.. HttpR ...
- JavaScript权威设计--事件冒泡,捕获,事件句柄,事件源,事件对象(简要学习笔记十八)
1.事件冒泡与事件捕获 2.事件与事件句柄 3.事件委托:利用事件的冒泡技术.子元素的事件最终会冒泡到父元素直到跟节点.事件监听会分析从子元素冒泡上来的事件. 事件委托的好处: 1.每个函 ...
- SharpGL学习笔记(十八) 解析3ds模型并显示
笔者设想的3D仿真中的元件,是不可能都是“画”出来的.这样就玩复杂了,应该把任务分包出去,让善于制作模型的软件来制作三维模型,我们只需要解析并且显示它即可. 3dsmax制作三维模型的方便,快捷,专业 ...
- C++学习笔记(八):函数重载、函数指针和函数对象
函数重载 函数重载是指在同一作用域内,可以有一组具有相同函数名,不同参数列表的函数,这组函数被称为重载函数.重载函数通常用来命名一组功能相似的函数,这样做减少了函数名的数量,避免了名字空间的污染,对于 ...
随机推荐
- SQL IIF函数的使用 判断为空数据不显示的问题
先说说IIF函数 IIF函数 需要一个条件 两个值 当条件满足的时候 执行第一个值 条件不满足的时候 执行第二个值 IIF(判断条件,值1,值2) 今天判断数据的时候 发现当值为NULL或者为' ...
- element-ui switch
<el-tooltip :content="'Switch value: ' + value" placement="top"> <el-sw ...
- software engineering homework 2
博客信息 沈阳航空航天大学计算机学院2020软件工程作业 作业要求 https://edu.cnblogs.com/campus/sau/Computer1701-1705/homework/1058 ...
- 十大经典排序之归并排序(C++实现)
归并排序 思路:(分而治之的思想) 1.申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列: 2.设定两个指针,最初位置分别为两个已经排序序列的起始位置: 3.比较两个指针所指向的元 ...
- wait_event_interruptible() 等待队列
在Linux驱动程序中,可以使用等待队列(Wait Queue)来实现阻塞进程的唤醒. 1.定义"等待队列头部" wait_queue_head_t my_queue; wait_ ...
- Cookie会话跟踪技术
cookie是什么 cookie 也叫 HTTPCookie,是客户端与服务器端进行会话(session)使用的一个能够在浏览器本地化存储的技术. cookie就是为了存储 sessionID而诞生. ...
- Java代码结构
Java代码结构 顺序结构 Java的基本结构为顺序结构,除非特别指明,否则从上到下一句一句执行 选择结构 if单选择结构 if(condition){ doSomething(); } if双选择结 ...
- idea的Tomcat的配置
1.创建一个web项目 2.创建项目完成后,配置 点击add 3.点击扳手 选择tomcat Server ----->Local 4.选择tomcat的文件夹路径 点击ok 5.再次点 ...
- K8S—dashboard ui部署
一.Dashboard UI概述 仪表板是基于Web的Kubernetes用户界面.您可以使用仪表板将容器化应用程序部署到Kubernetes集群,对容器化应用程序进行故障排除,并管理集群本身及其伴随 ...
- 随便记录一些使用IDEA在ssm阶段的踩过的坑
重命名中括号问题:需要重命名模块+目录 Intellij idea 报错:Error : java 不支持发行版本5_灵颖桥人的博客-CSDN博客_不支持发行版本5 idea中的目标字节码版本总是自动 ...