草庐IT

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

hunterxiong 2023-04-02 原文

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

  1. get_or_create
  2. update_or_create
  3. select_for_update
  4. bulk_create
  5. bulk_update

1、get_or_create

前面我们介绍过 get() 和 create() 的用法,那么 get_or_create() 的意思很简单,就是 获取或者创建,如果存在就返回,不存在就先创建再返回

假设对于 Blog model,我们想看下数据库有没有 name="hunter", tagline="tagline_test" 的数据,没有的话创建并获取这条数据,有的话,就直接获取。

在之前我们操作可能是:

try:
	blog = Blog.objects.get(name='hunter', tagline='tagline_test')
except Blog.DoesNotExist:
	blog = Blog(name='hunter', tagline='tagline_test')
	blog.save()		

现在我们可以直接这样操作:

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 来操作:

blog, created = Blog.objects.get_or_create(
	name='hunter', 
	tagline='tagline_test',
	defaults={
		'field_1': 'field_1_value',
		'field_2': 'field_2_value'
	}
)

最后关于这个函数,有个小提示,如果这个函数用在接口里,那么根据幂等性,我们应该使用 POST 方法来请求,而不是 GET 请求。

关于幂等性的概念,有兴趣的话可以去查询一下。

2、update_or_create

更新或者创建,使用方法同 get_or_create()

假设对于 Blog model 我们想实现的操作如果存在 name='hunter', tagline='tagline_test' 的数据就将其 field_1 和 field_2 的字段更新,不存在的话,就创建该数据。

之前的操作逻辑大概如下:

defaults = {"field_1": "field_1_value", "field_2": "field_2_value"}

try:
	obj = Blog.objects.get(name='hunter', tagline='tagline_test')
	for key, value in defaults.items():
		setattr(obj, key, value)
	obj.save()
except:
	new_values = {"name": "hunter", "tagline": "tagline_test}
	new_values.update(defaults)
	obj = Blog(**new_values)
	obj.save()

现在我们使用 update_or_create 可以如下操作:

obj, created = Blog.objects.update_or_create(
	name='hunter', tagline='tagline_test',
	defaults={"field_1": "field_1_value", "field_2": "field_2_value"}
)

3、select_for_update

select_for_update 的操作复杂一点,作用类似于 SQL 中的 SELECT ... FOR UPDATE 语句

操作如下:

from django.db import transaction

blog_list = Blog.objects.select_for_update().filter(name="hunter")
with transaction.atomic():
	for blog in blog_list:
		...

当 blog_list 去获取数据的时候,所有匹配上的 entries 都会被锁,直到这个事务结束。

意味着这个时候,其他的事务会被阻止更改或者重新在这些数据上加锁。

我们来举个例子,在我们执行下面的语句时:

import time
from django.db import transaction

blog_list = Blog.objects.select_for_update().filter(name="hunter")
with transaction.atomic():
	for blog in blog_list:
		print("locking ...")
		time.sleep(20)

这个时候,我们在重新开一个 shell,来执行下面的语句:

Blog.objects.filter(name="hunter").update(name="hunter_1")

因为第一个 shell 里执行的命令还没有结束,而且在数据上加了锁,因此第二个 shell 里的语句会进入等待,直到第一个 shell 里的命令执行完成之后,第二个 shell 里的命令才会执行。

注意: 如果在第一个命令里,对 blog 数据进行操作,比如 把 name 字段改为了 hunter_2,那么在第二条命令的条件里筛选不到结果然后更新的。

4、bulk_create

批量创建,在前面介绍增删改查的时候介绍过一次,这里再简单做一下示例:

from blog.models import Blog

blog_list = [
	Blog(name="hunter_1", tagline="tag_1"),
	Blog(name="hunter_2", tagline="tag_2"),
	Blog(name="hunter_3", tagline="tag_3"),
	Blog(name="hunter_4", tagline="tag_4")
]

Blog.objects.bulk_create(blog_list)

如果我们批量创建的数量过多,我们可以指定分批次来创建,通过 batch_size 参数来指定。

Blog.objects.bulk_create(blog_list, batch_size=2)

5、bulk_update

批量更新,方式与 bulk_create 的方式类似,以下是使用示例:

blog_list = Blog.objects.filter(id__lte=20)

for blog in blog_list:
	blog.name = "name_updated"
	blog.tagline = "tag_updated"

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等选择和更新等相关操作

如果想获取更多相关文章,可扫码关注阅读:

有关Django笔记十三之select_for_update等选择和更新等相关操作的更多相关文章

  1. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  2. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  3. ruby - 多个属性的 update_column 方法 - 2

    我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2

  4. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  5. ruby-on-rails - rspec should have_select ('cars' , :options => ['volvo' , 'saab' ] 不工作 - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion在首页我有:汽车:VolvoSaabMercedesAudistatic_pages_spec.rb中的测试代码:it"shouldhavetherightselect"dovisithome_pathit{shouldhave_select('cars',:options=>['volvo','saab','mercedes','audi'])}end响应是rspec./spec/request

  6. ruby-on-rails - Rails 中的 NoMethodError::MailersController#preview undefined method `activation_token=' for nil:NilClass - 2

    似乎无法为此找到有效的答案。我正在阅读Rails教程的第10章第10.1.2节,但似乎无法使邮件程序预览正常工作。我发现处理错误的所有答案都与教程的不同部分相关,我假设我犯的错误正盯着我的脸。我已经完成并将教程中的代码复制/粘贴到相关文件中,但到目前为止,我还看不出我输入的内容与教程中的内容有什么区别。到目前为止,建议是在函数定义中添加或删除参数user,但这并没有解决问题。触发错误的url是http://localhost:3000/rails/mailers/user_mailer/account_activation.http://localhost:3000/rails/mai

  7. ruby-on-rails - 相关表上的范围为 "WHERE ... LIKE" - 2

    我正在尝试从Postgresql表(table1)中获取数据,该表由另一个相关表(property)的字段(table2)过滤。在纯SQL中,我会这样编写查询:SELECT*FROMtable1JOINtable2USING(table2_id)WHEREtable2.propertyLIKE'query%'这工作正常:scope:my_scope,->(query){includes(:table2).where("table2.property":query)}但我真正需要的是使用LIKE运算符进行过滤,而不是严格相等。然而,这是行不通的:scope:my_scope,->(que

  8. ruby-on-rails - 如何重命名或移动 Rails 的 README_FOR_APP - 2

    当我在我的Rails应用程序根目录中运行rakedoc:app时,API文档是使用/doc/README_FOR_APP作为主页生成的。我想向该文件添加.rdoc扩展名,以便它在GitHub上正确呈现。更好的是,我想将它移动到应用程序根目录(/README.rdoc)。有没有办法通过修改包含的rake/rdoctask任务在我的Rakefile中执行此操作?是否有某个地方可以查找可以修改的主页文件的名称?还是我必须编写一个新的Rake任务?额外的问题:Rails应用程序的两个单独文件/README和/doc/README_FOR_APP背后的逻辑是什么?为什么不只有一个?

  9. ruby-on-rails - 复数 for fields_for has_many 关联未显示在 View 中 - 2

    目前,Itembelongs_toCompany和has_manyItemVariants。我正在尝试使用嵌套的fields_for通过Item表单添加ItemVariant字段,但是使用:item_variants不显示该表单。只有当我使用单数时才会显示。我检查了我的关联,它们似乎是正确的,这可能与嵌套在公司下的项目有关,还是我遗漏了其他东西?提前致谢。注意:下面的代码片段中省略了不相关的代码。编辑:不知道这是否相关,但我正在使用CanCan进行身份验证。routes.rbresources:companiesdoresources:itemsenditem.rbclassItemi

  10. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

随机推荐