Django的orm补充
Django的orm补充
参考文献:https://www.cnblogs.com/wupeiqi/articles/6216618.html
1.编写models示例
from django.db import models
class Foo(models.Model):
name=models.CharField(max_length=16)
class UserType(models.Model):
'''
用户类型
'''
title=models.CharField(max_length=16)
uf=models.ForeignKey(to='Foo',on_delete=models.CASCADE,null=True)
class UserInfo(models.Model):
'''
用户表
'''
username=models.CharField(max_length=16)
age=models.IntegerField()
ut=models.ForeignKey('UserType',on_delete=models.CASCADE)
models.IntegerField()
def __str__(self):
return "%s------%s"%(self.id,self.username)
2.排序分组
2.1 排序
def login_orm(request):
# 1.排序
user_list=models.UserInfo.objects.all()#此时默认从小到大排序
print(user_list)
return HttpResponse("加油!ORM 马上就要完成了!")
# user_list=models.UserInfo.objects.all()
# user_list=models.UserInfo.objects.all().order_by('-id')
user_list=models.UserInfo.objects.all().order_by('-id','name')#存在重复值则按照第二个值进行排序
2.2 分组
from django.db.models import Count
# 其他聚合函数的导入
# from django.db.models import Count,Max,Avg,Min
user=models.UserInfo.objects.values("ut_id").annotate()#不写聚合函数,相当于普通的sql
print(user.query)
user_list = models.UserInfo.objects.values("ut_id").annotate(xx=Count('id'))
print(user_list.query)
print(user_list)
# 使用sql语句中having可以直接在annotate()后面使用filter函数;
user_list=models.UserInfo.objects.values("ut_id").annotate(xx=Count('id')).filter(xx__gt=1)
print(user_list.query)
filter(id__gt=1)
在annotate前面表示where
,在annotate后面表示having
2.3 其他基本查询
# 3.其他基本查询
user1=models.UserInfo.objects.filter(id__lt=1)#小于1
user2=models.UserInfo.objects.filter(id__gt=1)#大于1
user3=models.UserInfo.objects.filter(id__lte=1)#小于等于1
print(user3.query)
user4 = models.UserInfo.objects.filter(id__gte=1) # 大于等于1
# 不等于
user=models.UserInfo.objects.exclude(id=1)#不等于1
print(user.query)
user5 = models.UserInfo.objects.filter(id__in=[1,2,3]) # in()
user6 = models.UserInfo.objects.filter(id__range=[1,3]) # 相当于Between
print(user6.query)
print(user5.query)
# 字符串字段中包含某些值的
user7=models.UserInfo.objects.filter(username__startswith='逻')#以某个值开头,也可以是其他字符串
user8=models.UserInfo.objects.filter(username__contains='尔')#字符串中包含某个值(字符串),
print(user7.query)
print(user8.query)
print(user7)
print(user8)
return HttpResponse("加油!ORM 马上就要完成了!")
-
补充:查看orm产生的sql语句可以使用
对象.query
3.F,Q查询
3.1 F更新操作
- 应用场景:将更改数据库中的值,并进行操作
# 1.F查询:通过F进行更新的操作。
from django.db.models import F
# 将数据库中所有的年龄进行+1
models.UserInfo.objects.all().update(age=F("age")+1)
3.2 Q查询的使用
-
使用场景:经常在
OR 使用 |
和and 使用 &
关系中使用,也会在动态增加筛选条件的时候进行使用(例如:CMDB项目); -
v=models.UserInfo.objects.filter(Q(id__gt=1)) print(v.query) print(v) v=models.UserInfo.objects.filter(Q(id=3)|Q(id=2)) print(v.query) print(v) v=models.UserInfo.objects.filter(Q(ut_id=1)&Q(id=1)) print(v.query) print(v)
-
-
-
q1=Q() q1.connector='OR' q1.children.append(('id__gt',1)) q1.children.append(('id',10)) q1.children.append(('id',9)) q2=Q() q2.connector='OR'#按照指定的子条件拼接对应语句 q2.children.append(('id',1)) q2.children.append(('id',2)) q2.children.append(('id',3)) con=Q() con.add(q1,'AND')#按照指定的关系拼接对应的Q对象 con.add(q2,'AND') v=models.UserInfo.objects.filter(con) print(v) print(v.query)
-
按照关系生成对应的 SQL 条件与关系
-
-
F,Q的总结
-
4.extra使用
4.1 使用
-
使用场景:较为复杂的 SQL 查询。(注:SQL 过于复杂时建议使用原生sql)
-
一般使用的时候建议边修改边打印 sql 进行修改。
-
# 3.extra v=models.UserInfo.objects.all().extra( select={'newid':'select count(1) from app01_usertype where id >%s'}, #相当于临时表 select_params=[1,],#按照位置传入Select中sql语句中占位符的值。 order_by=['-age'], tables=['app01_usertype'],#默认使用的是笛卡尔集 where=['age>%s'], params=[18,]#格式化where中的值; ) print(v) print(v.query) 产生的 sql 语句; SELECT (select count(1) from app01_usertype where id >1) AS "newid", "app01_userinfo"."id", "app01_userinfo"."username", "app01_userinfo"."age", "app01_userinfo"."ut_id" FROM "app01_userinfo" , "app01_usertype" WHERE (age>18) ORDER BY "app01_userinfo"."age" DESC
-
4.2 extra总结
- 补充:每个函数只要返回QuerySet的对象可以继续使用QuerySet的方法;相当于链式法则;
5. Django 执行原生sql
1.首先在配置文件中配置数据库的连接
2.在对应的模块中进行导入
from django.db import connection,connections
connection.connect()
conn = connection.connection
import pymysql
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
cursor.execute("""SELECT * from app01_userinfo""")
row = cursor.fetchone()
connection.close()
6.多个数据库
6.1 配置文件设置
6.2 使用
# 5.切换数据库
models.UserInfo.objects.all().using("db2")#models使用
from django.db import connection,connections
cursor=connections['db2'].cursor()# 原生SQL使用,db2默认使用的使用default,写入参数的就使用指定的数据库连接
7.补充:QuerSet函数
##################################################################
# PUBLIC METHODS THAT ALTER ATTRIBUTES AND RETURN A NEW QUERYSET #
##################################################################
def all(self)
# 获取所有的数据对象
def filter(self, *args, **kwargs)
# 条件查询
# 条件可以是:参数,字典,Q
def exclude(self, *args, **kwargs)
# 条件查询
# 条件可以是:参数,字典,Q
def select_related(self, *fields)
性能相关:表之间进行join连表操作,一次性获取关联的数据。
model.tb.objects.all().select_related()
model.tb.objects.all().select_related('外键字段')
model.tb.objects.all().select_related('外键字段__外键字段')
def prefetch_related(self, *lookups)
性能相关:多表连表操作时速度会慢,使用其执行多次SQL查询在Python代码中实现连表操作。
# 获取所有用户表
# 获取用户类型表where id in (用户表中的查到的所有用户ID)
models.UserInfo.objects.prefetch_related('外键字段')
from django.db.models import Count, Case, When, IntegerField
Article.objects.annotate(
numviews=Count(Case(
When(readership__what_time__lt=treshold, then=1),
output_field=CharField(),
))
)
students = Student.objects.all().annotate(num_excused_absences=models.Sum(
models.Case(
models.When(absence__type='Excused', then=1),
default=0,
output_field=models.IntegerField()
)))
def annotate(self, *args, **kwargs)
# 用于实现聚合group by查询
from django.db.models import Count, Avg, Max, Min, Sum
v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id'))
# SELECT u_id, COUNT(ui) AS `uid` FROM UserInfo GROUP BY u_id
v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')).filter(uid__gt=1)
# SELECT u_id, COUNT(ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1
v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id',distinct=True)).filter(uid__gt=1)
# SELECT u_id, COUNT( DISTINCT ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1
def distinct(self, *field_names)
# 用于distinct去重
models.UserInfo.objects.values('nid').distinct()
# select distinct nid from userinfo
注:只有在PostgreSQL中才能使用distinct进行去重
def order_by(self, *field_names)
# 用于排序
models.UserInfo.objects.all().order_by('-id','age')
def extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
# 构造额外的查询条件或者映射,如:子查询
Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))
Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])
def reverse(self):
# 倒序
models.UserInfo.objects.all().order_by('-nid').reverse()
# 注:如果存在order_by,reverse则是倒序,如果多个排序则一一倒序
def defer(self, *fields):
models.UserInfo.objects.defer('username','id')
或
models.UserInfo.objects.filter(...).defer('username','id')
#映射中排除某列数据
def only(self, *fields):
#仅取某个表中的数据
models.UserInfo.objects.only('username','id')
或
models.UserInfo.objects.filter(...).only('username','id')
def using(self, alias):
指定使用的数据库,参数为别名(setting中的设置)
##################################################
# PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS #
##################################################
def raw(self, raw_query, params=None, translations=None, using=None):
# 执行原生SQL
models.UserInfo.objects.raw('select * from userinfo')
# 如果SQL是其他表时,必须将名字设置为当前UserInfo对象的主键列名
models.UserInfo.objects.raw('select id as nid from 其他表')
# 为原生SQL设置参数
models.UserInfo.objects.raw('select id as nid from userinfo where nid>%s', params=[12,])
# 将获取的到列名转换为指定列名
name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'}
Person.objects.raw('SELECT * FROM some_other_table', translations=name_map)
# 指定数据库
models.UserInfo.objects.raw('select * from userinfo', using="default")
################### 原生SQL ###################
from django.db import connection, connections
cursor = connection.cursor() # cursor = connections['default'].cursor()
cursor.execute("""SELECT * from auth_user where id = %s""", [1])
row = cursor.fetchone() # fetchall()/fetchmany(..)
def values(self, *fields):
# 获取每行数据为字典格式
def values_list(self, *fields, **kwargs):
# 获取每行数据为元祖
def dates(self, field_name, kind, order='ASC'):
# 根据时间进行某一部分进行去重查找并截取指定内容
# kind只能是:"year"(年), "month"(年-月), "day"(年-月-日)
# order只能是:"ASC" "DESC"
# 并获取转换后的时间
- year : 年-01-01
- month: 年-月-01
- day : 年-月-日
models.DatePlus.objects.dates('ctime','day','DESC')
def datetimes(self, field_name, kind, order='ASC', tzinfo=None):
# 根据时间进行某一部分进行去重查找并截取指定内容,将时间转换为指定时区时间
# kind只能是 "year", "month", "day", "hour", "minute", "second"
# order只能是:"ASC" "DESC"
# tzinfo时区对象
models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.UTC)
models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.timezone('Asia/Shanghai'))
"""
pip3 install pytz
import pytz
pytz.all_timezones
pytz.timezone(‘Asia/Shanghai’)
"""
def none(self):
# 空QuerySet对象
####################################
# METHODS THAT DO DATABASE QUERIES #
####################################
def aggregate(self, *args, **kwargs):
# 聚合函数,获取字典类型聚合结果
from django.db.models import Count, Avg, Max, Min, Sum
result = models.UserInfo.objects.aggregate(k=Count('u_id', distinct=True), n=Count('nid'))
===> {'k': 3, 'n': 4}
def count(self):
# 获取个数
def get(self, *args, **kwargs):
# 获取单个对象
def create(self, **kwargs):
# 创建对象
def bulk_create(self, objs, batch_size=None):
# 批量插入
# batch_size表示一次插入的个数
objs = [
models.DDD(name='r11'),
models.DDD(name='r22')
]
models.DDD.objects.bulk_create(objs, 10)
def get_or_create(self, defaults=None, **kwargs):
# 如果存在,则获取,否则,创建
# defaults 指定创建时,其他字段的值
obj, created = models.UserInfo.objects.get_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 2})
def update_or_create(self, defaults=None, **kwargs):
# 如果存在,则更新,否则,创建
# defaults 指定创建时或更新时的其他字段
obj, created = models.UserInfo.objects.update_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 1})
def first(self):
# 获取第一个
def last(self):
# 获取最后一个
def in_bulk(self, id_list=None):
# 根据主键ID进行查找
id_list = [11,21,31]
models.DDD.objects.in_bulk(id_list)
def delete(self):
# 删除
def update(self, **kwargs):
# 更新
def exists(self):
# 是否有结果
其他操作