翼度科技»论坛 编程开发 python 查看内容

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

5

主题

5

帖子

15

积分

新手上路

Rank: 1

积分
15
本文首发于微信公众号:Hunter后端
原文链接:Django笔记十八之save函数的继承操作和指定字段更新等实例方法
这篇笔记主要介绍 Django 一些实例方法。
什么是 实例,我们知道通过filter() 的一些筛选方法,得到的是 QuerySet,而 QuerySet 取单条数据,通过索引,或者 first() 或者 last() 等方法,得到的单条数据,就是一个 model 的实例。
我们接下来要介绍的就是这种单条实例的一些方法。

  • save() 的继承操作
  • refresh from db, 从数据库中更新实例数据
  • 自增的主键
  • 指定字段更新 save()
1、save() 的继承操作

对于一个 model,我们可以通过 save() 的方式创建一条数据,比如:
  1. from blog.models import Blog
  2. blog = Blog(name="blog_1", tagline="tagline_1")
  3. blog.save()
复制代码
对于上面的 blog,我们就称其为 Blog 的一个实例。
我们可以通过继承覆盖原有的 save() 方法,然后新增一些我们需要的操作,比如打印日志,发送提醒等。
方法如下:
  1. class Blog(models.Model):
  2.     name = models.CharField(max_length=100)
  3.     tagline = models.TextField()
  4.     def save(self, *args, **kwargs):
  5.         print("save")
  6.         super(Blog, self).save(*args, **kwargs)
复制代码
这样,我们在对  Blog 数据进行 save() 操作的时候,就可以看到控制台会输出 "save" 的记录。
除此之外,Django 的文档提出了一种方式,在 model 中定义一个类方法,可以方便我们对数据进行处理:
  1. class Blog(models.Model):
  2.     name = models.CharField(max_length=100)
  3.     tagline = models.TextField()
  4.     @classmethod
  5.     def create(cls, name, tagline):
  6.         blog = cls(name=name, tagline=tagline)
  7.         print("get an unsaved Blog instance")
  8.         return blog
复制代码
然后通过调用该方法,传入参数,可以得到一个未保存的实例:
  1. from blog.models import Blog
  2. blog = Blog.create(name='test_create', tagline='test_tagline')
  3. blog.save()
复制代码
注意: 在我们执行 create() 方法的时候,程序还没有操作数据库,只是得到一个未保存的实例,我们仍然需要执行 save() 操作才能保存到数据库。
除了这种方法,还有一种官方文档更推荐的方法,就是使用 manager,这个的用法我们在后面几篇笔记中涉及,这里只做一个展示:
  1. class BlogManager(models.Manager):
  2.     def create_blog(self, name, tagline):
  3.         blog = self.create(name=name, tagline=tagline)
  4.         # do something with the blog
  5.         print("get an unsaved Blog instance")
  6.         return blog
  7. class Blog(models.Model):
  8.     name = models.CharField(max_length=100)
  9.     tagline = models.TextField()
  10.     objects = BlogManager()
复制代码
需要注意的是,这里调用的是 create() 方法,所以直接保存到了数据库,不用再执行 save() 方法了。
2、refresh from db, 从数据库中更新实例数据

方法为 refresh_from_db()
作用为从数据库中获取实例数据的最新值。
  1. blog = Blog.objects.first()
  2. # 其他地方可能会对 blog 数据进行一些更改
  3. # 然后从数据库中拉取 blog 的最新数据
  4. 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 字段赋值。
  1. b = Blog.objects.first()
  2. b.id = None
  3. b.save()
  4. b.id
复制代码
4、指定字段更新 save()

假设有一个 TestModel,有一个 number 字段,我们想要对其执行 +1 的操作,大概行为可能如下:
  1. obj = TestModel.objects.get(id=1)
  2. obj.number += 1
  3. obj.save()
复制代码
我们也可以通过 F() 函数这种稍微快一点和避免竞争的方式(竞争的意思是,其他的进程可能也在使用这条数据):
  1. from django.db.models import F
  2. obj = TestModel.objects.get(id=1)
  3. obj.number = F('number') + 1
  4. obj.save()
复制代码
指定字段保存
单纯的使用 save() 操作可能会造成一个问题,比如说,我们在某一个 get 了一条数据,对 name 字段进行了更改,但同时另一个进程对同一条数据也进行了更改,我们对这条数据进行 save() 操作,那么就可能造成数据不一致的情况。
  1. blog = Blog.objects.get(id=1)
  2. blog.name = "test_1"
  3. # 在这个期间,另一个进程对 tagline 字段进行了更改
  4. # 假设该操作为 Blog.objects.filter(id=1).update(tagline="new_tagline")
  5. # 然后执行 save() 操作
  6. blog.save()
复制代码
那么这个时候,blog 的数据因为已经从数据库中获取了出来,再执行 save() 则会保存之前获取的数据,这样会导致在此期间对 tagline 字段进行的更新操作还原。
那么这个时候,为了避免这种情况发生,我们在 save() 的时候指定我们要更新的字段来保存数据:
  1. blog.name = "test_1"
  2. blog.save(update_fields=["name"])
复制代码
以上就是本篇笔记全部内容,下一篇笔记将介绍 manager 的用法。
如果想获取更多相关文章,可扫码关注阅读:


来源:https://www.cnblogs.com/hunterxiong/p/17294394.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具