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

Django笔记十三之select_for_update等选择和更新等相关操作

7

主题

7

帖子

21

积分

新手上路

Rank: 1

积分
21
本篇笔记将介绍 update 和 create 的一些其他用法,目录如下:

  • get_or_create
  • update_or_create
  • select_for_update
  • bulk_create
  • bulk_update
1、get_or_create

前面我们介绍过 get() 和 create() 的用法,那么 get_or_create() 的意思很简单,就是 获取或者创建,如果存在就返回,不存在就先创建再返回
假设对于 Blog model,我们想看下数据库有没有 name="hunter", tagline="tagline_test" 的数据,没有的话创建并获取这条数据,有的话,就直接获取。
在之前我们操作可能是:
  1. try:
  2.         blog = Blog.objects.get(name='hunter', tagline='tagline_test')
  3. except Blog.DoesNotExist:
  4.         blog = Blog(name='hunter', tagline='tagline_test')
  5.         blog.save()               
复制代码
现在我们可以直接这样操作:
  1. blog, created = Blog.objects.get_or_create(name='hunter', tagline='tagline_test')
复制代码
这个函数的返回值有两个,一个是操作的 model 实例,一个是是否是 created 的 布尔型数据。
created 为 True,表示这条数据是创建,create() 到的
created 为 False,表示这条数据是获取, get() 到的
注意: 查询的条件必须是唯一的,否则会造成多条数据返回而报错,这个逻辑同 get() 函数。
注意: 使用的字段,没有唯一的约束,并发的调用这个方法可能会导致多条相同的值插入。
字段默认值
假设 Blog 这个 model 除了 name, tagline 这两个字段外,还有 field_1 和 field_2 字段,但是他们不在我们查询的条件内,作用为在创建的时候设置的默认值,我们可以通过 defaults 来操作:
  1. blog, created = Blog.objects.get_or_create(
  2.         name='hunter',
  3.         tagline='tagline_test',
  4.         defaults={
  5.                 'field_1': 'field_1_value',
  6.                 'field_2': 'field_2_value'
  7.         }
  8. )
复制代码
最后关于这个函数,有个小提示,如果这个函数用在接口里,那么根据幂等性,我们应该使用 POST 方法来请求,而不是 GET 请求。
关于幂等性的概念,有兴趣的话可以去查询一下。
2、update_or_create

更新或者创建,使用方法同 get_or_create()
假设对于 Blog model 我们想实现的操作如果存在 name='hunter', tagline='tagline_test' 的数据就将其 field_1 和 field_2 的字段更新,不存在的话,就创建该数据。
之前的操作逻辑大概如下:
  1. defaults = {"field_1": "field_1_value", "field_2": "field_2_value"}
  2. try:
  3.         obj = Blog.objects.get(name='hunter', tagline='tagline_test')
  4.         for key, value in defaults.items():
  5.                 setattr(obj, key, value)
  6.         obj.save()
  7. except:
  8.         new_values = {"name": "hunter", "tagline": "tagline_test}
  9.         new_values.update(defaults)
  10.         obj = Blog(**new_values)
  11.         obj.save()
复制代码
现在我们使用 update_or_create 可以如下操作:
  1. obj, created = Blog.objects.update_or_create(
  2.         name='hunter', tagline='tagline_test',
  3.         defaults={"field_1": "field_1_value", "field_2": "field_2_value"}
  4. )
复制代码
3、select_for_update

select_for_update 的操作复杂一点,作用类似于 SQL 中的 SELECT ... FOR UPDATE 语句
操作如下:
  1. from django.db import transaction
  2. blog_list = Blog.objects.select_for_update().filter(name="hunter")
  3. with transaction.atomic():
  4.         for blog in blog_list:
  5.                 ...
复制代码
当 blog_list 去获取数据的时候,所有匹配上的 entries 都会被锁,直到这个事务结束。
意味着这个时候,其他的事务会被阻止更改或者重新在这些数据上加锁。
我们来举个例子,在我们执行下面的语句时:
  1. import time
  2. from django.db import transaction
  3. blog_list = Blog.objects.select_for_update().filter(name="hunter")
  4. with transaction.atomic():
  5.         for blog in blog_list:
  6.                 print("locking ...")
  7.                 time.sleep(20)
复制代码
这个时候,我们在重新开一个 shell,来执行下面的语句:
  1. Blog.objects.filter(name="hunter").update(name="hunter_1")
复制代码
因为第一个 shell 里执行的命令还没有结束,而且在数据上加了锁,因此第二个 shell 里的语句会进入等待,直到第一个 shell 里的命令执行完成之后,第二个 shell 里的命令才会执行。
注意: 如果在第一个命令里,对 blog 数据进行操作,比如 把 name 字段改为了 hunter_2,那么在第二条命令的条件里筛选不到结果然后更新的。
4、bulk_create

批量创建,在前面介绍增删改查的时候介绍过一次,这里再简单做一下示例:
  1. from blog.models import Blog
  2. blog_list = [
  3.         Blog(name="hunter_1", tagline="tag_1"),
  4.         Blog(name="hunter_2", tagline="tag_2"),
  5.         Blog(name="hunter_3", tagline="tag_3"),
  6.         Blog(name="hunter_4", tagline="tag_4")
  7. ]
  8. Blog.objects.bulk_create(blog_list)
复制代码
如果我们批量创建的数量过多,我们可以指定分批次来创建,通过 batch_size 参数来指定。
  1. Blog.objects.bulk_create(blog_list, batch_size=2)
复制代码
5、bulk_update

批量更新,方式与 bulk_create 的方式类似,以下是使用示例:
  1. blog_list = Blog.objects.filter(id__lte=20)
  2. for blog in blog_list:
  3.         blog.name = "name_updated"
  4.         blog.tagline = "tag_updated"
  5. Blog.objects.bulk_update(blog_list, fields=['name'], batch_size=2)
复制代码
需要注意的是 bulk_update 多了个参数,fields 这个是用来指定需要更新的字段。
如我们上面的命令所示,我们指定更新的是 name 字段,那么就算我们更改了 tagline 的数据,只要 fields 列表里没有指定该字段,那么后台也不会更新该字段。
以上就是本篇笔记全部内容,接下来我们将介绍一下查询中的其他用法,比如latest,first,contains 等。
本文首发于本人微信公众号:Hunter后端
原文链接:Django笔记十三之select_for_update等选择和更新等相关操作
如果想获取更多相关文章,可扫码关注阅读:


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

本帖子中包含更多资源

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

x

举报 回复 使用道具