原文作者:我辈理想
版权声明:文章原创,转载时请务必加上原文超链接、作者信息和本声明。
提示:这里可以添加本文要记录的大概内容:
我们都知道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)
先声明Product类,然后向类中写入内容。
product = Product()
product.user_id =1
product.name='测试项目'
product.type ='0'
product.save()
# product.save(user_id =1,name='测试项目',type ='0')
product = Product(
user_id =1,
name='测试项目',
type ='0'
)
product.save()
Product.objects.create(user_id =1,name='测试项目',type ='0')
在实际web开发中,前后端传输数据多是json格式,通过字典创建数据可以更方便,代码量更少(减少数据转换的过程)。
dict = {
'user_id':1,
'name':'测试项目',
'type':'0',
}
Product.objects.create(**dict)
这里id是Product创建时默认的主键,get方法只能获取一条,参数需要是唯一值,否则报错
Product.objects.get(id=1)
Product.objects.all()
Product.objects.all().order_by('id')[0:3] # 前三条
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()
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字段,找出包含‘项目’二字的数据
在实际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)
django的聚合查询主要是orm的2个方法,aggregate和annotate +values_list或values
基本思路是aggregate是聚合方法,总是进行运算,如果想要获得多样数据需要使用annotate,与values完成分组查询结果是字典,与values_list结果是元组(flat参数将获得列表)。
更新数据可以参考创建数据,但需要注意的是更新时的条件和更新的内容。
p = Product.objects.get(id=1)
p.name = '测试项目2'
p.save()
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)
Product.objects.get(id=1).delete()
Product.objects.filter(id=1).delete()
批量创建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)
批量修改筛选后的数据,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'"})
queryset = []
queryset.extend(queryset_1)
queryset.extend(queryset_2)
queryset.extend(queryset_3)
queryset_1.union(queryset_2, queryset_3)
orm针对外键提供了跨表查询参数select_related、prefetch_related、Prefetch() 对象。这些是性能提升器,它会导致一个更复杂的查询,但意味着以后使用外键关系不需要数据库查询。
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
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的实际使用还有很多方法,需要按照需求找到对应的方法和方式。