【Django】如何实现ORM的增删改查和批量操作

原文作者:我辈理想
版权声明:文章原创,转载时请务必加上原文超链接、作者信息和本声明。

文章目录

  • 前言
  • 一、创建数据:create或save
    • (一)save创建
      • 1.每个字段赋值
      • 2.models类赋值
    • (二)create
      • 1.基本创建
      • 2.使用字典创建
  • 二、获取一条数据:get
  • 三、获取全部数据:all
      • 1.查询
      • 2.切片
  • 四、筛选多条数据:filter
      • 1.filter使用
      • 2.flter进阶
      • 3.动态查询+模糊查询
      • 4.聚合查询
  • 五、更新数据:save或update
      • 1.save更新
      • 2.update更新
  • 六、删除数据:delete
  • 七、批量创建:bulk_create
  • 八、批量更新:bulk_update
  • 九、嵌套查询
  • 十、扩展查询
  • 十一、查询拼接
    • 1.内存拼接
    • 2.数据库拼接
  • 十二、跨表查询优化
    • 1.select_related只适合ForeignKey和OneToOneField
    • 2.prefetch_related适合ManyToManyField
  • 总结


前言

提示:这里可以添加本文要记录的大概内容:

我们都知道Django框架默认是通过ORM来实现数据的增删改查,涉及到的orm方法为create、delete、update、get、filter、all、get_or_create、update_or_create。在Django中还有批量操作,如批量创建和批量更新,涉及到的方法为bulk_create、bulk_update。
本片博客主要结合python数据结构字典,更方便的使用这些方法。

我们应该准备models.py文件,样例如下,详细请看下文。

from django.contrib.gis.db import models
from django.utils import timezone

from django.utils.translation import gettext_lazy as _  # _作为国际化标记,实现中英文翻译


Product_Type = (
    ('0', _('洪水检测')),
    ('1', _('船只提取')),
)
class Product(models.Model):
    user_id = models.IntegerField('在User表中的编号', default=0)
    name = models.CharField("名称", max_length=32, default="")
    type = models.CharField('类型', max_length=20, choices=Product_Type, default='0')
    sort = models.IntegerField(verbose_name='排序', default=0)
    memo = models.CharField(verbose_name='备注', max_length=100, null=True)

    create_time = models.DateTimeField('创建时间', default=timezone.now)
    alter_time = models.DateTimeField(verbose_name='修改时间', auto_now=True)

    class Mate:
        verbose_name = '产品'
        verbose_name_plural = verbose_name

    def __str__(self):
        return str(self.name)

一、创建数据:create或save

(一)save创建

先声明Product类,然后向类中写入内容。

1.每个字段赋值

product = Product()
product.user_id =1
product.name='测试项目'
product.type ='0'
product.save()
# product.save(user_id =1,name='测试项目',type ='0')

2.models类赋值

product = Product(
	user_id =1,
	name='测试项目',
	type ='0'
)
product.save()

(二)create

1.基本创建

Product.objects.create(user_id =1,name='测试项目',type ='0')

2.使用字典创建

在实际web开发中,前后端传输数据多是json格式,通过字典创建数据可以更方便,代码量更少(减少数据转换的过程)。

dict = {
	'user_id':1,
	'name':'测试项目',
	'type':'0',
}
Product.objects.create(**dict)

二、获取一条数据:get

这里id是Product创建时默认的主键,get方法只能获取一条,参数需要是唯一值,否则报错

Product.objects.get(id=1)

三、获取全部数据:all

1.查询

Product.objects.all()

2.切片

Product.objects.all().order_by('id')[0:3]  # 前三条

四、筛选多条数据:filter

1.filter使用

Product.objects.filter(user_id=1)
Product.objects.filter(user_id=1,type ='0')
Product.objects.filter(user_id=1).filter(type ='0')
Product.objects.filter(user_id=1).first()

2.flter进阶

filter是ORM的常用功能,里面很多参数可以使用,除了直接查询外,还有一些封装的方法可以使用,包括__in、__lte、__gte、__icontains

Product.objects.filter(user_id__in=[1,2,3,4,5])  # 查询1,2,3,4,5这个5个人的Product数据
Product.objects.filter(create_time__gte=datetime.datetime(year=2022,month=12,day=12))  # 查询创建时间在2022年12月12日0点之后的数据
Product.objects.filter(Q(name__icontains='项目') OR Q(memo__icontains='项目'))  # 模糊查询name或memo字段,找出包含‘项目’二字的数据

3.动态查询+模糊查询

在实际web开发中,前后端传输数据多是json格式,通过字典创建数据可以更方便,代码量更少(减少数据转换的过程)。
通过是Q查询,扩展查询能力

dict = {
	'user_id':1,
	'name':'测试项目',
	'create_time__gte':datetime.datetime(year=2022,month=12,day=12)
}

q = Q()
q_name = Q(name__icontains='项目')
q_memo = Q(memo__icontains='项目')
q.add(q_name, 'OR')
q.add(q_memo, 'OR')
Product.objects.filter(**dict).filter(q)

4.聚合查询

django的聚合查询主要是orm的2个方法,aggregate和annotate +values_list或values

基本思路是aggregate是聚合方法,总是进行运算,如果想要获得多样数据需要使用annotate,与values完成分组查询结果是字典,与values_list结果是元组(flat参数将获得列表)。

五、更新数据:save或update

更新数据可以参考创建数据,但需要注意的是更新时的条件和更新的内容。

1.save更新

p = Product.objects.get(id=1)
p.name = '测试项目2'
p.save()

2.update更新

Product.objects.fliter(id=1).update(user_id =1,name='测试项目2',type ='0')

在实际web开发中,前后端传输数据多是json格式,通过字典创建数据可以更方便,代码量更少(减少数据转换的过程)。

dict = {
	'user_id':1,
	'name':'测试项目',
	'type':'0',
}
Product.objects.filter(user_id=1).update(**dict)

六、删除数据:delete

Product.objects.get(id=1).delete()
Product.objects.filter(id=1).delete()

七、批量创建:bulk_create

批量创建4条数据

name_list = ['测试项目1','测试项目2','测试项目3','测试项目4']
create_list = []
for name in name_list:
	product = Product(
		user_id =1,
		name=name,
		type ='0'
	)
	create_list.append(product)
Product.objects.bulk_create(create_list)

八、批量更新:bulk_update

批量修改筛选后的数据,batch_size这里需要注意这个参数,网络上没有详细说怎么用。
通过查看bulk_update源码可以知道batch_size参数会将ORM查询按照batch_size的数量分段,然后执行分段数量的sql修改,假如我们有百万条数据,如果使用update一次更新,底层的sql将太长无法执行,bulk_update的batch_size设置为10000,那么bulk_update将执行100条sql修改语句,保证sql能够正常执行,batch_size根据更新字段的多少调整。

# 将用户1的数据,全部转移至用户2账户下
ps = Product.objects.filter(user_id=1)
for p in ps:
	p.user_id=2
Product.objects.bulk_update(ps,fields=['filepath'], batch_size=1000)

九、嵌套查询

嵌套查询会将orm拼接成一个sql语句,这个很多时候是我们希望的,但需要熟悉查询内容和数据库的相关性能,以下是嵌套查询示例。

inner_qs = Blog.objects.filter(name__contains='Ch').values('name', 'id')
entries = Entry.objects.filter(blog__name__in=inner_qs)

因为orm是惰性的,如果不想使用嵌套,可以使用如下示例:

values = Blog.objects.filter(
        name__contains='Cheddar').values_list('pk', flat=True)
entries = Entry.objects.filter(blog__in=list(values))
# 应为list,会执行2次查询

十、扩展查询

这个针对于不同数据库处理复杂where语句提供扩展查询

Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})

十一、查询拼接

1.内存拼接

queryset = []
queryset.extend(queryset_1)
queryset.extend(queryset_2)
queryset.extend(queryset_3)

2.数据库拼接

queryset_1.union(queryset_2, queryset_3)

十二、跨表查询优化

orm针对外键提供了跨表查询参数select_related、prefetch_related、Prefetch() 对象。这些是性能提升器,它会导致一个更复杂的查询,但意味着以后使用外键关系不需要数据库查询。

1.select_related只适合ForeignKey和OneToOneField

select_related 使用的是数据库的连表查询INNER JOIN。以下示例中blog是外键。

下边这个示例是2次查询

# Hits the database.
e = Entry.objects.get(id=5)

# Hits the database again to get the related Blog object.
b = e.blog

下边这个示例是1次查询

# Hits the database.
e = Entry.objects.select_related('blog').get(id=5)

# Doesn't hit the database, because e.blog has been prepopulated
# in the previous query.
b = e.blog

2.prefetch_related适合ManyToManyField

prefetch_related大致与select_related 相同,并且在此基础上使用python缓存all查询。

很多次查询

plist = Person.objects.prefetch_related('visitation')
[p.visitation.filter(name__icontains=u"市") for p in plist]

2次查询

plist = Person.objects.prefetch_related('visitation')
[[city for city in p.visitation.all() if u"市" in city.name] for p in plist]

Prefetch对象是prefetch_related的应用。可以将prefetch_related和select_related一起使用。

链锁 prefetch_related 调用将累积预取的查找。清除任何 prefetch_related
prefetch_cleared_qset = qset.prefetch_related(None)

总结

ORM的实际使用还有很多方法,需要按照需求找到对应的方法和方式。

你可能感兴趣的:(Django开始入门,django,python,后端)