本文首发于微信公众号:Hunter后端

原文链接:Django笔记十八之save函数的继承操作和指定字段更新等实例方法

这篇笔记主要介绍 Django 一些实例方法。

什么是 实例,我们知道通过filter() 的一些筛选方法,得到的是 QuerySet,而 QuerySet 取单条数据,通过索引,或者 first() 或者 last() 等方法,得到的单条数据,就是一个 model 的实例。

我们接下来要介绍的就是这种单条实例的一些方法。

  1. save() 的继承操作
  2. refresh from db, 从数据库中更新实例数据
  3. 自增的主键
  4. 指定字段更新 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函数的继承操作和指定字段更新等实例方法的更多相关文章

  1. python3.4学习笔记(十八) pycharm 安装使用、注册码、显示行号和字体大小等常用设置

    python3.4学习笔记(十八) pycharm 安装使用.注册码.显示行号和字体大小等常用设置Download JetBrains Python IDE :: PyCharmhttp://www. ...

  2. (C/C++学习笔记) 十八. 继承和多态

    十八. 继承和多态 ● 继承的概念 继承(inheritance): 以旧类为基础创建新类, 新类包含了旧类的数据成员和成员函数(除了构造函数和析构函数), 并且可以派生类中定义新成员. 形式: cl ...

  3. python 学习笔记十八 django深入学习三 分页,自定义标签,权限机制

    django  Pagination(分页) django 自带的分页功能非常强大,我们来看一个简单的练习示例: #导入Paginator>>> from django.core.p ...

  4. Opencv笔记(十八)——轮廓的更多函数及其层次结构

    凸缺陷 前面我们已经学习了轮廓的凸包,对象上的任何凹陷都被成为凸缺陷.OpenCV 中有一个函数 cv.convexityDefect() 可以帮助我们找到凸缺陷.函数调用如下: hull = cv2 ...

  5. Django(十八)Model操作补充

    参考博客:http://www.cnblogs.com/wupeiqi/articles/6216618.html 1. 创建类 class UserInfo(model.Model): age = ...

  6. 嵌入式Linux驱动笔记(十八)------浅析V4L2框架之ioctl【转】

    转自:https://blog.csdn.net/Guet_Kite/article/details/78574781 权声明:本文为 风筝 博主原创文章,未经博主允许不得转载!!!!!!谢谢合作 h ...

  7. django 笔记8 url模板 自定义函数 simple_tag

    感谢alex老师~ 知识点: URL - 两个没见 url>路由系统> 函数或类 > 返回字符串 Form表单提交: 提交 >url>函数或类中的方法 -.. HttpR ...

  8. JavaScript权威设计--事件冒泡,捕获,事件句柄,事件源,事件对象(简要学习笔记十八)

    1.事件冒泡与事件捕获 2.事件与事件句柄   3.事件委托:利用事件的冒泡技术.子元素的事件最终会冒泡到父元素直到跟节点.事件监听会分析从子元素冒泡上来的事件. 事件委托的好处:     1.每个函 ...

  9. SharpGL学习笔记(十八) 解析3ds模型并显示

    笔者设想的3D仿真中的元件,是不可能都是“画”出来的.这样就玩复杂了,应该把任务分包出去,让善于制作模型的软件来制作三维模型,我们只需要解析并且显示它即可. 3dsmax制作三维模型的方便,快捷,专业 ...

  10. C++学习笔记(八):函数重载、函数指针和函数对象

    函数重载 函数重载是指在同一作用域内,可以有一组具有相同函数名,不同参数列表的函数,这组函数被称为重载函数.重载函数通常用来命名一组功能相似的函数,这样做减少了函数名的数量,避免了名字空间的污染,对于 ...

随机推荐

  1. MySql Host is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'

    错误:Host is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts' 原因:同一个ip ...

  2. 如何安装vm虚拟机软件并用该软件建立虚拟机

    一.安装vm虚拟机软件 1.双击打开虚拟机应用程序 找到VM应用程序所在的位置,双击安装 2.根据向导安装 根据提示点击下一步 点击安装之后耐心等待一会,会出现需要输入许可证的的界面,这时候不要关闭界 ...

  3. C语言初级阶段5——函数2

    C语言初级阶段5--函数2 址传递 1.地址:在定义变量,数组,函数等等,系统会自动给分配他们的内存区域(地址),把这个数据放到这个地址上面. 2.&:&a 得到a的地址编号 3.*: ...

  4. ZFBJ - 1 - 42 - NO.1

  5. html超链接相关代码

    1. <IDOCTYPE html>< html><head><title>图像和超链接</title><meta http-equi ...

  6. Eclipse's Content Assist

    在Eclipse里面的辅助智能索引只有"."才会提示,或者手动按alt+/补全提示.因为Eclipse的补全功能的默认设置只有".",其实你只需要稍微修改一下就 ...

  7. Linux拷贝以及赋权

    拷贝     cp -r  /源文件/* 目标文件/&     //&后台运行符 改变权限  sudo chown -R 用户:群组  文件名           // sudo ch ...

  8. C#软件增加混淆防止反编译

    使用Visual Studio新建一个名为"test"的命令行项目输入如图所示的代码并生成项目,这个项目很简单,就是程序启动时,调用"GetGUID"函数返回一 ...

  9. Linux查看CPU 内存命令

    查看CPU 内存命令:https://www.cnblogs.com/ggjucheng/archive/2013/01/14/2859613.html 查看某一进程内存占用:ps -ef 获取PID ...

  10. mac下webstrom卡顿快速解决办法

    vim /Applications/WebStorm.app/Contents/bin/webstorm.vmoptions 一路回车 直到看到: 按insert 将顶部以下两项原有值修改为以下值: ...