Django默认ORM(五):常用操作数据的方法
1、我们平时用到的数据库的基本增删改查:
models.UserInfo.objects.all() models.UserInfo.objects.filter(id=1,id=2) models.UserInfo.objects.all().first() models.UserInfo.objects.all().count() models.UserInfo.objects.all().update() models.UserInfo.objects.all().delete() models.UserInfo.objects.all()[1:19] #取第一条到第18条数据 跨表:实质上是先进行连表操作,再进行的where筛选,最后显示的列名 正向: xxxx.filter(ut__title='值').values('id','name','ut__title') 反向: xxxx.filter(小写表名称__列名='值').values('id','name','小写表名称__列名') - 示例:打印原sql语句看看,查看QuerySet里取出的字典 #正向先过滤后取值 obj = models.UserInfo.objects.filter(ut__title="白银用户").values("id","name","ut__title") print(obj.query) print(obj) """ SELECT "app01_userinfo"."id", "app01_userinfo"."name", "app01_usertype"."title" FROM "app01_userinfo" INNER JOIN "app01_usertype" ON("app01_userinfo"."ut_id" = "app01_usertype"."id") WHERE "app01_usertype"."title" = 白银用户 < QuerySet[{'id': 6, 'name': 'ada1', 'ut__title': '白银用户'}] > """ #反向先过滤后取值 obj = models.UserType.objects.filter(userinfo="3").values("userinfo__name","userinfo__age","title",) print(obj.query) print(obj) """SELECT "app01_userinfo"."name", "app01_userinfo"."age", "app01_usertype"."title" FROM "app01_usertype" INNER JOIN "app01_userinfo" ON ("app01_usertype"."id" = "app01_userinfo"."ut_id") WHERE "app01_userinfo"."id" = 3 <QuerySet [{'userinfo__name': 'ada2', 'userinfo__age': 19, 'title': '黄金用户'}]> """
2、过滤/条件判断<等同于 where>:
__gt --->大于 __gte ---> 大于等于 __lt ---> 小于 __lte ---> 小于等于 __in = [] ----> 获取 xx 在列表中的值 相当于in 例:id__in = [1,2,3,4,5] __range=[] ----> 范围查找 相当于between and __contains="xxx" -----> 包含 __startswith = "xxxxx" ----->起始值 __endswith = "xxxxx" ----->结尾 .exclude(列名__in=[列表值]) 获取不在列表内的值,相当于 not in - 示例: models.UserInfo.objects.filter(id__gt=1) models.UserInfo.objects.filter(id__lt=1) models.UserInfo.objects.filter(id__lte=1) models.UserInfo.objects.filter(id__gte=1) models.UserInfo.objects.filter(id__in=[1,2,3]) models.UserInfo.objects.filter(id__range=[1,2]) models.UserInfo.objects.filter(name__startswith='xxxx') models.UserInfo.objects.filter(name__endswith='xxxx') models.UserInfo.objects.filter(name__contains='xxxx') models.UserInfo.objects.exclude(id=1)
3、排序:.order_by("列名") <等同于order by 列名 asc or desc> 可以通过多个列名排序!
- 语法: 对象.order_by("id") #默认排序是从小到大 对象.order_by("-id") #从大到小排序 - 示例: user_list = models.UserInfo.objects.values("id","name","age").order_by("id") #从小到大排 user_list = models.UserInfo.objects.values("id","name","age").order_by("-id") #从大到小排 user_list = models.UserInfo.objects.values("id","name","age").order_by("id","name") #先按照id从小到大排,如果有重复的再按照name从小到大排列 print(user_list)
4、分组:.annotate(别名=聚合函数(列名)) <等同于 group by > annotate的本意是注释,此处是分组
- 语法: from django.db.models import Count,max,min,Sum,…… #使用前先导入聚合函数 .annotate(别名=Count(列名)) 二次筛选----->在分组之后.filter(别名的条件)<__gt:大于;__lt:小于> - 示例: from django.db.models import Count v = models.UserInfo.objects.values("ut_id").annotate(othername = Count("id")) #用于查看sql语句 上条语句的实质是以values中的列作为分组的列,此处values和annotate存在关系 # 如果annotate 中不写任何语句,则只是查看数据包中对应的这列的数据! print(v.query) print(v) v1 = models.UserInfo.objects.values("ut_id").filter(ut_id__gte=2).annotate(othername = Count("id")).filter(othername__gt=1) #查看sql语句发现,第一个filter等同于where,第二个filter等同于 having print(v1.query) print(v1)
5、更新F:
用于获取表中某列的原始数据 常用于更新操作.update() from django.db.models import F #导入模块 models.UserInfo.objects.all().update(age=F("age")+1)
6、Q查询:
#补充:查询条件是字典类型,将字典作为条件进行筛选 condition = { 'id':1, 'name': 'root' } v = models.UserInfo.objects.filter(**condition) #结果为obj对象 - 常用于数据的筛选.filter() 用于构造复杂的查询条件 - Q使用有两种方式:对象方式,方法方式*** from django.db.models import Q #导入模块 应用一:对象 组合判断 from django.db.models import Q user_list = models.UserInfo.objects.values("id","name").filter(Q(id__gt=1)) #单个Q对象 user_list = models.UserInfo.objects.values("id","name").filter(Q(id=2)| Q(id=3)) # 多个Q对象 或关系关联 user_list = models.UserInfo.objects.values("id","name").filter(Q(id=2) & Q(name="rain1")) # 多个Q对象 与关系关联 print(user_list) 应用二:先创建方法,然后添加条件 q1 = Q() #生成Q对象 q1.connector = "OR" #指定多个对象间连接的关系 q1.children.append(("id__gt",1)) #添加的数据:必须是元组类型,第一个是条件,第二个是值 q1.children.append(("id__lt",5)) q2 = Q() q2.connector = "AND" q2.children.append(("id",1)) q2.children.append(("id",2)) conn = Q() #生成一个Q对象 conn.add(q1,"AND") #以某种关系,添加其他的Q对象 conn.add(q2,"AND") v = models.UserInfo.objects.all().filter(conn) #通过条件去查找对应数据 print(v) - 若是查询信息是字典格式,想转成Q对象的方法: condition_dict = { 'k1': [1, 2, 3, 4], 'k2': [1, ], } con = Q() for k, v in condition_dict.items(): q = Q() q.connector = 'OR' for i in v: q.children.append(('id', i)) con.add(q, 'AND') user_list = models.UserInfo.objects.filter(con)
7、extra额外查询条件以:
***当django定义的规则无法完成或是无法满足需求的时候,就需要用到以下两种方式,进行对数据库的操作!
作用:(额外查询条件以及相关表,排序)用于子查询,再从别处获取点数据 除filter外可以在外边添加extra,这是同时生效的。 语法:.extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None) 使用分类: a. 映射 select = {"别名":"带占位符的原生sql语句"} select_params=[按顺序要传递的值] #select 此处 from 表 b. 条件 where=["字符串类型的条件(有占位符)",] params=[传值], # select * from 表 where 此处 c. 表 tables = ["表"] # select * from 表,此处 d. 排序 order_by=["列名"] # select * from 表 order by 此处 - 示例: v = models.UserInfo.objects.all().extra( select={ 'n':"select count(1) from app01_usertype where id=%s or id=%s", 'm':"select count(1) from app01_usertype where id=%s or id=%s", }, select_params=[1,2,3,4]) for obj in v: print(obj.name,obj.id,obj.n,obj.m) v = models.UserInfo.objects.extra( where=["id=1","name='alex'"] ) v = models.UserInfo.objects.extra( where=["id=1 or id=%s ","name=%s"], params=[1,"alex"] ) v = models.UserInfo.objects.extra( tables=['app01_usertype'], ) # sql语句"""select * from app01_userinfo,app01_usertype""" 查询两个表,以笛卡尔基的方式显示多条数据 models.UserInfo.objects.extra( tables=['app01_usertype'], where = ["app01_usertype.id = app01_userinfo.ut_id"], order_by = ["-app01_userinfo.id"], ) # sql语句"""select * from app01_userinfo,app01_usertype where app01_usertype.id = app01_userinfo.ut_id""" 连表操作,where判断 print(v.query) #查看对应的sql语句 - 所有方法操作: v = models.UserInfo.objects.filter(id__gt=3).extra( tables=["app01_usertype"], select={"title":"select title from app01_usertype where id >%s"}, select_params=[1,], where=["app01_userinfo.age>%s","app01_userinfo.ut_id = app01_usertype.id",], params=[16,], order_by=["-app01_userinfo.id"] ) print(v.query) """ SELECT (select title from app01_usertype where id >1) AS "title", "app01_userinfo"."id", "app01_userinfo"."name", "app01_userinfo"."age", "app01_userinfo"."ut_id" FROM "app01_userinfo" , "app01_usertype" WHERE ("app01_userinfo"."id" > 3 AND (app01_userinfo.age>16) AND (app01_userinfo.ut_id = app01_usertype.id)) ORDER BY ("app01_userinfo".id) DESC """
8、原生sql语句:
- 当ORM操作无法完成的时候,我们就需要写原生的sql语句来实现这个操作数据库的功能 from django.db import connection, connections #首先先导入模块 connection 默认连接settings文件中对应的 default 库 connections["数据库"] ----> 选择连接settings中设置的不同数据库 #注意:django的机制会连接上数据库,我们就利用现成的连接,访问数据库,创建游标,写原生sql语句并提交。不需要考虑关闭连接的问题。 #谨慎一些可以把创建的游标关闭,数据库连接由django去做判断 #创建不同类型的游标 cursor = connection.cursor() # connection=default数据 cursor = connections['db2'].cursor() cursor.execute("""SELECT * from auth_user where id = %s""", [1]) #向数据库提交数据 row = cursor.fetchone() #接收查到的单个信息 row = cursor.fetchall() #接收查到的所有信息 总结: 可以写sql语句的方法: 1、原生sql语句, 2、extra 3、raw
9、其他操作:
1 ################################################################## 2 # PUBLIC METHODS THAT ALTER ATTRIBUTES AND RETURN A NEW QUERYSET # 3 ################################################################## 4 5 def all(self) 6 # 获取所有的数据对象 7 8 def filter(self, *args, **kwargs) 9 # 条件查询 10 # 条件可以是:参数,字典,Q 11 12 def exclude(self, *args, **kwargs) 13 # 条件查询 14 # 条件可以是:参数,字典,Q 15 16 def select_related(self, *fields) 17 #性能相关:表之间进行join连表操作,一次性获取关联的数据。 18 model.tb.objects.all().select_related() 19 model.tb.objects.all().select_related('外键字段') 20 model.tb.objects.all().select_related('外键字段__外键字段') 21 22 def prefetch_related(self, *lookups) 23 #性能相关:多表连表操作时速度会慢,使用其执行多次SQL查询在Python代码中实现连表操作。 24 # 获取所有用户表 25 # 获取用户类型表where id in (用户表中的查到的所有用户ID) 26 models.UserInfo.objects.prefetch_related('外键字段') 27 28 29 from django.db.models import Count, Case, When, IntegerField 30 Article.objects.annotate( 31 numviews=Count(Case( 32 When(readership__what_time__lt=treshold, then=1), 33 output_field=CharField(), 34 )) 35 ) 36 37 students = Student.objects.all().annotate(num_excused_absences=models.Sum( 38 models.Case( 39 models.When(absence__type='Excused', then=1), 40 default=0, 41 output_field=models.IntegerField() 42 ))) 43 - 以上两种连表操作方法总结: 44 优点:约束,节省磁盘空间 45 缺点:性能不高,连表越多,性能越差 46 47 对于连表,操作少量的数据表显现不出性能的缺点, 48 但是对于大数据的表,或者是访问量巨大,同时追求响应速度的网站,查看搜索数据过大,再加上连表操作的时候,缺点就会显现。 49 针对这种情况,大公司都是舍弃磁盘,把数据都放在一个表里操作以提高性能! 50 51 #select_related: 查询主动做连表。<性能相对的会降低> 52 # 操作机制:通过外键名,先做连表操作把数据都放在一个对象里,对象再通过外键名.列名去获取数据,而不再做二次查询。 53 v = models.UserInfo.objects.all().select_related("ut",……) #括号内可以写多个外键名,前提是当前表内有多个 54 for row in v: 55 print(row.id,row.name,row.age,row.ut.title) 56 57 #prefetch_related: 不做连表,做多次查询。 58 <避免影响性能,django自己通过外键[过滤之后的]作为条件,对多表都先查询,然后django内部对查询到的结果做连表操作> 59 q = models.UserInfo.objects.all().prefetch_related("ut",……) #括号内可以写多个外键名,前提是当前表内有多个 60 for row in q: 61 print(row.id,row.name,row.age,row.ut.title) 62 63 64 def annotate(self, *args, **kwargs) 65 # 用于实现聚合group by查询 66 67 from django.db.models import Count, Avg, Max, Min, Sum 68 69 v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')) 70 # SELECT u_id, COUNT(ui) AS `uid` FROM UserInfo GROUP BY u_id 71 72 v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')).filter(uid__gt=1) 73 # SELECT u_id, COUNT(ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1 74 75 v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id',distinct=True)).filter(uid__gt=1) 76 # SELECT u_id, COUNT( DISTINCT ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1 77 78 def distinct(self, *field_names) 79 # 用于distinct去重 80 models.UserInfo.objects.values('nid').distinct() 81 # select distinct nid from userinfo 82 83 注:只有在PostgreSQL中才能使用distinct进行去重 84 85 def order_by(self, *field_names) 86 # 用于排序 87 models.UserInfo.objects.all().order_by('-id','age') 88 89 def extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None) 90 # 构造额外的查询条件或者映射,如:子查询 91 92 Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,)) 93 Entry.objects.extra(where=['headline=%s'], params=['Lennon']) 94 Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"]) 95 Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid']) 96 97 def reverse(self): 98 # 倒序 99 models.UserInfo.objects.all().order_by('-nid').reverse() 100 # 注:如果存在order_by,reverse则是倒序,如果多个排序则一一倒序 101 #倒序:只有前边有order_by操作的时候才起作用,否则不起任何作用!倒序只是反转 按照 某列分组 的排序规则 102 103 104 def defer(self, *fields): 105 models.UserInfo.objects.defer('username','id') 106 或 107 models.UserInfo.objects.filter(...).defer('username','id') 108 #映射中排除某列数据 109 #defer 获取除了条件列外所有的数据 110 111 def only(self, *fields): 112 #仅取某个表中的数据 113 models.UserInfo.objects.only('username','id') 114 或 115 models.UserInfo.objects.filter(...).only('username','id') 116 117 #only 只获取条件内的列所对应的数据 118 v = models.UserInfo.objects.all().only("id","name") 119 #操作之后的结果还是obj对象,只是对象内的数据只有id和name,当然也可以通过这个对象去获取其他列的信息,就会再往数据库发送一次查询请求! 120 #所以说,取了哪个就获取哪个,不要再获取额外的数据! 121 122 def using(self, alias): 123 #指定使用的数据库,参数为别名(setting中的设置) 124 #多个数据库的情况下:using用于指定去某个数据库中取数据,不写默认是default。当然,前提是数据库里得有要操作的表。 125 models.UserInfo.objects.all().using("数据库名") 126 #注意点:数据库操作拿到的对象相同,就能一直调用这个对象对应的方法。obj对象就可以。 127 128 ################################################## 129 # PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS # 130 ################################################## 131 132 def raw(self, raw_query, params=None, translations=None, using=None): 133 # 执行原生SQL 134 models.UserInfo.objects.raw('select * from userinfo') 135 136 # 如果SQL是其他表时,必须将名字设置为当前UserInfo对象的主键列名 137 models.UserInfo.objects.raw('select id as nid from 其他表') 138 139 # 为原生SQL设置参数 140 models.UserInfo.objects.raw('select id as nid from userinfo where nid>%s', params=[12,]) 141 142 # 将获取的到列名转换为指定列名 143 name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'} 144 Person.objects.raw('SELECT * FROM some_other_table', translations=name_map) 145 146 # 指定数据库 147 models.UserInfo.objects.raw('select * from userinfo', using="default") 148 149 ################### 原生SQL ################### 150 from django.db import connection, connections 151 cursor = connection.cursor() # cursor = connections['default'].cursor() 152 cursor.execute("""SELECT * from auth_user where id = %s""", [1]) 153 row = cursor.fetchone() # fetchall()/fetchmany(..) 154 - 示例: 155 #sql语句,查询本表 156 v = models.UserInfo.objects.raw("select * from app01_userinfo") 157 print(v) 158 print(v.query) 159 for i in v: 160 print(i.id,i.name) 161 """ 162 <RawQuerySet: select * from app01_userinfo> 163 select * from app01_userinfo 164 """ 165 #查询另一张表,由于两张表的id名相同,Userinfo在生成对象的时候,会根据id再对自己的表进行一次查询。拿到自己表对应的数据。 166 #而sql语句中要找的title列信息,不会存在Userinfo的对象中。 167 v = models.UserInfo.objects.raw("select id,title from app01_usertype") 168 print(v) 169 print(v.query) 170 for i in v: 171 print(i.id,i.name) 172 #SQL是其他表,将名字设置为当前UserInfo表中相对应的列名<id名相同>, 173 # UserInfo生成对象的时候,就会把sql语句中查到的数据,按照列名存放<对应的自己表的数据不取,此时就是对sql语句起一个包装的作用> 174 175 176 177 v = models.UserInfo.objects.raw("select id,title as name from app01_usertype") 178 print(v) 179 print(v.query) 180 for i in v: 181 print(i.id,i.name) 182 #将获取到的列名,转换成指定列名 自定义名 = {"获取的列名":"指定列名",.....} 183 name_map = {"id":"id","title":"name"} 184 v = models.UserInfo.objects.raw("select * from app01_usertype",translations=name_map).using("default") 185 print(v) 186 print(v.query) 187 for i in v: 188 print(i.id, i.name) 189 190 191 def values(self, *fields): 192 # 获取每行数据为字典格式 193 194 def values_list(self, *fields, **kwargs): 195 # 获取每行数据为元祖 196 #对数据库存放的时间进行截取操作,通过关键字去截取。 197 def dates(self, field_name, kind, order='ASC'): 198 # 根据时间进行某一部分去重查找并截取指定内容 199 # kind只能是:"year"(年), "month"(年-月), "day"(年-月-日) 200 # order只能是:"ASC" "DESC" 201 # 并获取转换后的时间 202 - year : 年-01-01 203 - month: 年-月-01 204 - day : 年-月-日 205 206 models.DatePlus.objects.dates('ctime','day','DESC') 207 208 209 def datetimes(self, field_name, kind, order='ASC', tzinfo=None): 210 # 根据时间进行某一部分进行去重查找并截取指定内容,将时间转换为指定时区时间 211 # kind只能是 "year", "month", "day", "hour", "minute", "second" 212 # order只能是:"ASC" "DESC" 213 # tzinfo时区对象 214 models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.UTC) 215 models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.timezone('Asia/Shanghai')) 216 217 """ 218 pip3 install pytz 219 import pytz 220 pytz.all_timezones 221 pytz.timezone(‘Asia/Shanghai’) 222 """ 223 224 def none(self): 225 # 空QuerySet对象,什么都不取 226 227 #################################### 228 # METHODS THAT DO DATABASE QUERIES # 229 #################################### 230 231 232 233 234 235 def aggregate(self, *args, **kwargs): 236 # 聚合函数,获取字典类型聚合结果 237 #聚合不分组,把整个表看成一个组进行计算,返回相关聚合函数操作次数的结果。 238 from django.db.models import Count, Avg, Max, Min, Sum 239 240 result = models.UserInfo.objects.aggregate(k=Count('u_id',), n=Count('nid')) #不对数据进行去重 241 ===>{"k":6,"n":6} 242 result = models.UserInfo.objects.aggregate(k=Count('u_id', distinct=True), n=Count('nid')) #对数据进行去重 243 ===> {'k': 3, 'n': 6} 244 245 def count(self): 246 # 获取个数 247 248 def get(self, *args, **kwargs): 249 # 获取单个对象 250 #get(条件) 能找到数据正常,找不到对应的数据就会报错;找到一条数据正常,找到多条数据会报错; 251 def create(self, **kwargs): 252 # 创建对象 253 #增加会有返回值,表示当前增加的数据,通过obj.id 获取新增的id。 254 obj = models.UserInfo.objects.create(XXXXX) 255 print(obj.id) 256 257 258 259 260 261 262 263 def bulk_create(self, objs, batch_size=None): 264 # 批量插入 265 # batch_size表示一次插入的个数 266 objs = [ 267 models.UserInfo(name='r11'), #注意插入数据的类型,没有object 268 models.UserInfo(name='r22') 269 ] 270 models.UserInfo.objects.bulk_create(objs, 10) #batch_size:批量增加,每次最多提交对象的个数,最多不要操作999。 271 272 def get_or_create(self, defaults=None, **kwargs): 273 # 如果存在,则获取,否则,创建 274 #查找的条件可以有多个,若是存在,则defaults内的字段全部作废,否则创建一条新的数据 275 # defaults 指定创建时,其他字段的值 276 obj, created = models.UserInfo.objects.get_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 2}) 277 278 def update_or_create(self, defaults=None, **kwargs): 279 # 如果存在,则更新,否则,创建 280 # defaults 指定创建时或更新时的其他字段 281 obj, created = models.UserInfo.objects.update_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 1}) 282 283 def first(self): 284 # 获取第一个 285 286 def last(self): 287 # 获取最后一个 288 289 290 def in_bulk(self, id_list=None): 291 # 根据主键ID进行查找 292 #根据主键进行查询,相当于是in操作,判断主键在不在条件中。 293 id_list = [11,21,31] 294 models.UserInfo.objects.in_bulk(id_list) 295 296 def delete(self): 297 # 删除 298 299 def update(self, **kwargs): 300 # 更新 301 302 def exists(self): 303 # 是否有结果 304 #查看新增之后的数据存不存在,返回的是布尔值。