本文首发于微信公众号: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. 20220719 第七组 陈美娜 Java(this,封装,构造器概念)

    1.关于构造器 如果说创建对象仅仅是为了调用这个类的方法,建议使用无参构造器 如果说创建对象的时候需要使用到对象的某个属性,可以使用构造器赋值 2.this关键字 this代表的是当前类的对象,thi ...

  2. NODEJS的误打误撞

    我接触nodejs 纯属是误打误撞,之前在做一个房地产项目的时候,客户提出了一个需求,我大概整理一些"我们需要员工只能在公司登陆房管系统并进行操作,回家是不允许进行登录的",其实对 ...

  3. vue + vant 移动端适配

    1. 设置动态根字号大小,/public/phone-adapt.js,在index.html中引入 (function (doc, win) { const docEl = win.document ...

  4. 【线性DP】乌龟棋

    #include<bits/stdc++.h> using namespace std; int a[400],b[5]; int dp[50][50][50][50]; int main ...

  5. Float浮动、 CSS定位(position)

    Float浮动. CSS定位(position)1.CSS定位机制(1)普通流(标准流)-默认状态,元素自动从左往右,从上往下的排列(2)浮动-会使元素向左或向右移动,只能左右,不能上下-浮动元素碰到 ...

  6. JS和PHP中能转为布尔false的值的对比

    实际开发中经常会使用到JS和PHP中的变量转布尔值进行条件判断,下面对两种语言中转布尔类型结果为false的值进行对比,加深记忆和方便引用. 除了下表列出项,其它的值均转成真值true . 转布尔值后 ...

  7. GPU Skinning

    这个工具的作用是同一种角色在同屏里面出现一大堆时,可以大幅度的降低DrawCall.我试了一下,感觉挺有意思的,各位可以试试.它的原理实际上是把骨骼矩阵存在配置文件里面,然后通过特殊的shader,计 ...

  8. 关于python print函数format 格式化

    关于python print函数format 格式化  Your Guide to the Python print() Function https://realpython.com/python- ...

  9. Blazor项目在VisualStudio调试时配置运行基础目录

    最近在使用 Blazor 开发管理后台时遇到了如下的问题,我这里后台整体采用了 AntDesignBlazor 组件库,在上线之后发现ReuseTabs组件在使用过程中,如果默认 / 没有指定为项目的 ...

  10. MySQL基础随笔记

    [1]SQL语言入门      我们都知道,数据库管理人员(DBA)通过数据库管理系统(DBMS)可以对数据库(DB)中的数据进行操作,但具体是如何操作的呢?这就涉及到我们本节要讲的SQL语言.SQL ...