本文首发于微信公众号: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. java整合SSM框架

    使用Myeclipse搭建maven项目 准备工作 安装maven 官网下载安装(http://maven.apache.org/)    配置环境变量      配置完后,使用命令行输入mvn -v ...

  2. C++中,get getline gets 用法

    1.cin 2.cin.get() 3.cin.getline() 4.getline() 5.gets() 6.getchar() 1.cin>> 用法1:最基本,也是最常用的用法,输入 ...

  3. LSP原则中的逆变和协变

    在复习过程中,LSP原则是个很重要的内容.这里先给出LSP原则的定义. LSP定义Functions that use pointers or referrnces to base classes m ...

  4. js- throw and try-catch-finally

    总结一下: 1.throw 抛出错误 2.在使用try-catch时 try{}抛出错误,catch{}块语句才执行,另外catch(e)可创建例如e的标识符,对try{}块抛出异常进行捕捉 3.在使 ...

  5. Python+Django(2)——创建应用程序

    新打开一个终端窗口,切换到manage.py所在的目录 激活虚拟环境:ll_env\Scripts\activate 命令startapp appname 让Django建立创建应用程序所需的基础设施 ...

  6. ceph 因权重问题导致pgs active+clean+remapped 状态

    1.现象: 2.原因:是因为前期权重调整不合理导致,调整回来就正常了 3.操作步骤: ceph osd crush reweight osd.2 0.98317    # osd 位置. 权重值 权重 ...

  7. 文献学习——A Deep Dive into Conflict Generating Decisions

    A Deep Dive into Conflict Generating Decisions Md. Solimul Chowdhury, Martin Müller, Jia-Huai You:A  ...

  8. .NetCore中配置Ef

    1.在NuGet中下载 Microsoft.EntityFrameworkCore.Tools Microsoft.EntityFrameworkCore.SqlServer 2.需要在Api层.实现 ...

  9. AT212 P-CASカードと高橋君

    题目描述 高桥君为了准备即将到来的7月27日土用丑日,打算邮购一些高级鳗鱼食材,通过网上银行来支付. 高桥君使用的银行卡背面有下图所示的9×9密码表.支付的时候从表中某一位置开始根据指定的方向连续读4 ...

  10. CSS网页布局基础

    CSS网页布局基础1.行布局-基础的行布局-行布局自适应-行布局自适应限制最大宽-行布局垂直水平居中-行布局某部位自适应-行布局固定宽-行布局导航随屏幕滚动2.多列布局-两列布局固定-两列布局自适应- ...