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++学习笔记(八):函数重载、函数指针和函数对象
函数重载 函数重载是指在同一作用域内,可以有一组具有相同函数名,不同参数列表的函数,这组函数被称为重载函数.重载函数通常用来命名一组功能相似的函数,这样做减少了函数名的数量,避免了名字空间的污染,对于 ...
随机推荐
- 329MD5的加密
一.引用帮助类 二.登录的代码
- Day1.无敌难受且成功
Markdown学习 标题 字体 ctrl+b.l.u.k加粗.斜体.下划线.超链接 引用 大于号+空格 分割线 三个*** ###都 图片 !+[]+() 英文输入法的符号 输入的图片路径可本地也要 ...
- re相关正则表达式(re.sub、re.I 、re.S、re.M)
re.I 表示忽略大小写 re.S 表示全文匹配 re.M 表示全文拼配行尾段位的字符或者数字,影响^和$ re.sub 表示替换 使用方法: re.sub(pattern, repl, string ...
- 安装 TensorFlow 参考过的资料
anaconda 的新环境创建 https://blog.csdn.net/yandajiangjun/article/details/102615912
- js数组常用的方法
var arr=['hello','前端','world']; 1. arr.join(分隔符):将数组中的值拼接成一个字符串,返回这个字符串,默认分隔符"," arr.join( ...
- 狂神的学习笔记demo11(包机制)
无法生成子包的问题:设置图标里的Compact Middle Packages勾去掉 //定义包 package package com.panda.base1; //导入包import import ...
- tensorboard可视化详细
tensorboard可视化详细 2019-09-06 tensorboard可视化的官方学习链接 1.tensorboard可视化的用途 首要的目的是记录tensorflow的Graph,tenso ...
- java输入一个字符串,要求将该字符串中出现的英文字母, * 按照顺序输出,区分大小写,且大写优先
public static void main(String[] args) { String input ="A8r4c5jaAjp#7"; //转为char[] char[] ...
- QT网络编程【一】
1.QUdpSocket头文件无法识别怎么解决? 问题原因:qmake没有添加network的模块.在工程配置文件中添加配置即可. 2.选择c++的socket库还是QUdpSocket? 3.同样的 ...
- CentOS 安装 jdk1.8
转自:https://www.cnblogs.com/yjlch1016/p/8900841.html 前置条件:不使用openjdk,若想使用openjdk.直接在centos下 使用 yum 查 ...