Django Model ORM(对象关系映射) 操作详解
一,基本操作 用于实现面向对象编程语言里不同类型系统的数据之间的转换,换言之,就是用面向对象的方式去操作数据库的创建表以及增删改查等操作。 1.增(create,save): from?app01.models?import?* #create方式一:??? Author.objects.create(name='Alvin') ???? #create方式二:??? Author.objects.create(**{"name":"alex"}) ???? #save方式一:????? author=Author(name="alvin")??????????????? author.save() ???????????????????? #save方式二:????? author=Author() author.name="alvin" author.save() 2.删(delete): #正向???? book?=?models.Book.objects.filter(id=1) #删除第三张表中和女孩1关联的所有关联信息 book.author.clear()????????#清空与book中id=1?关联的所有数据 book.author.remove(2)??????#可以为id book.author.remove(*[1,2,3,4])?????#可以为列表,前面加* #反向 author?=?models.Author.objects.filter(id=1) author.book_set.clear()?#清空与boy中id=1?关联的所有数据 3.改(update和save): update方法直接设定对应属性 models.Tb1.objects.filter(name='seven').update(gender='0')??#?将指定条件的数据更新,均支持?**kwargs save方法会将所有属性重新设定一遍,效率低 obj?=?models.Tb1.objects.get(id=1) obj.c1?=?'111' obj.save() 4.查 #?获取个数 models.Tb1.objects.filter(name='seven').count() #?大于,小于 models.Tb1.objects.filter(id__gt=1)??????#?获取id大于1的值 models.Tb1.objects.filter(id__gte=1)?????#?获取id大于等于1的值 models.Tb1.objects.filter(id__lt=10)?????#?获取id小于10的值 models.Tb1.objects.filter(id__lte=10)????#?获取id小于10的值 models.Tb1.objects.filter(id__lt=10,?id__gt=1)???#?获取id大于1?且?小于10的值 #?in models.Tb1.objects.filter(id__in=[11,?22,?33])???#??获取id等于11、22、33的数据 models.Tb1.objects.exclude(id__in=[11,?33])??#?not?in #?isnull Entry.objects.filter(pub_date__isnull=True) #?contains models.Tb1.objects.filter(name__contains="ven") models.Tb1.objects.filter(name__icontains="ven")?icontains大小写不敏感 models.Tb1.objects.exclude(name__icontains="ven") #?range models.Tb1.objects.filter(id__range=[1,?2])???范围bettwen?and #?其他类似 startswith,istartswith,?endswith,?iendswith,#?order?by models.Tb1.objects.filter(name='seven').order_by('id')????asc models.Tb1.objects.filter(name='seven').order_by('-id')???desc #?group?by from?django.db.models?import?Count,?Min,?Max,?Sum models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num')) SELECT?"app01_tb1"."id",?COUNT("app01_tb1"."num")?AS?"c"?FROM?"app01_tb1"?WHERE?"app01_tb1"."c1"?=?1?GROUP?BY?"app01_tb1"."id" #?limit?、offset models.Tb1.objects.all()[10:20] #?regex正则匹配,iregex?不区分大小写 Entry.objects.get(title__regex=r'^(An?|The)?+') Entry.objects.get(title__iregex=r'^(an?|the)?+') #?date Entry.objects.filter(pub_date__date=datetime.date(2005,?1,?1)) Entry.objects.filter(pub_date__date__gt=datetime.date(2005,?1)) #?year Entry.objects.filter(pub_date__year=2005) Entry.objects.filter(pub_date__year__gte=2005) #?month Entry.objects.filter(pub_date__month=12) Entry.objects.filter(pub_date__month__gte=6) #?day Entry.objects.filter(pub_date__day=3) Entry.objects.filter(pub_date__day__gte=3) #?week_day Entry.objects.filter(pub_date__week_day=2) Entry.objects.filter(pub_date__week_day__gte=2) #?hour Event.objects.filter(timestamp__hour=23) Event.objects.filter(time__hour=5) Event.objects.filter(timestamp__hour__gte=12) #?minute Event.objects.filter(timestamp__minute=29) Event.objects.filter(time__minute=46) Event.objects.filter(timestamp__minute__gte=29) #?second Event.objects.filter(timestamp__second=31) Event.objects.filter(time__second=2) Event.objects.filter(timestamp__second__gte=31) 查询相关API
<1>?all():?????????????????查询所有结果 ? <2>?filter(**kwargs):??????它包含了与所给筛选条件相匹配的对象 ? <3>?get(**kwargs):?????????返回与所给筛选条件相匹配的对象,返回结果有且只有一个, ???????????????????????????如果符合筛选条件的对象超过一个或者没有都会抛出错误。 ? <5>?exclude(**kwargs):?????它包含了与所给筛选条件不匹配的对象 ? <4>?values(*field):????????返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列 ???????????????????????????model的实例化对象,而是一个可迭代的字典序列 ? <9>?values_list(*field):???它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列 ? <6>?order_by(*field):??????对查询结果排序 ? <7>?reverse():?????????????对查询结果反向排序 ? <8>?distinct():????????????从返回结果中剔除重复纪录 ? <10>?count():??????????????返回数据库中匹配查询(QuerySet)的对象数量。 ? <11>?first():??????????????返回第一条记录 ? <12>?last():???????????????返回最后一条记录 ? <13>?exists():?????????????如果QuerySet包含数据,就返回True,否则返回False 二、连表操作 利用双下划线和 _set 将表之间的操作连接起来 2.1 一对一操作 user_info_obj?=?models.UserInfo.objects.filter(id=1).first() print?user_info_obj.user_type print?user_info_obj.get_user_type_display() print?user_info_obj.userprofile.password ? user_info_obj?=?models.UserInfo.objects.filter(id=1).values('email',?'userprofile__username').first() print?user_info_obj.keys() print?user_info_obj.values() 2.2 一对多操作 1、搜索条件使用 __ 连接 2、获取值时使用 . 连接 2.3 多对多三级联动models class?Province(models.Model): ????name?=?models.CharField(max_length=32) class?City(models.Model): ????name?=?models.CharField(max_length=32) ????pro?=?models.ForeignKey("Province") class?Xian(models.Model): ????name?=?models.CharField(max_length=32) ????cy?=?models.ForeignKey("City") views def?menu(request): ????#?for?i?in?range(10): ????#?????models.Province.objects.create(name="河北"+str(i)) ????#?for?i?in?range(5): ????#?????models.City.objects.create(name="廊坊"?+?str(i),pro_id=1) ????#?return?HttpResponse("OK") ????pro_list?=?models.Province.objects.all() ????return?render(request,?'menus.html',?{"pro_list":?pro_list}) def?fetch_city(request): ????#?根据用户传入的省份ID,获取与其相关的所有市ID ????#?ret?=?{'status':?True,?'error':?None,?'data':?None} ????province_id?=?request.GET.get('province_id') ????#?result?=?models.City.objects.filter(pro_id=province_id) ????#?#?QuerySet内部放置对象 ????#?from?django.core?import?serializers ????#?data?=?serializers.serialize("json",?result) ????result?=?models.City.objects.filter(pro_id=province_id).values('id','name') ????#?QuerySet内部放置对象 ????result?=?list(result) ????import?json ????data?=?json.dumps(result) ????#?result?=?models.City.objects.filter(pro_id=province_id).values_list('id','name') ????#?#?QuerySet内部放置对象 ????#?print(result) ????#?result?=?list(result) ????#?import?json ????#?data?=?json.dumps(result) ????return?HttpResponse(data) def?fetch_xian(request): ????#?for?i?in?range(10): ????#?????models.Xian.objects.create(name='县'+?str(i),?cy_id=1) ????city_id?=?request.GET.get('city_id') ????xian_list?=?models.Xian.objects.filter(cy_id=city_id).values('id','name') ????xian_list?=?list(xian_list) ????return?HttpResponse(json.dumps(xian_list)) menu.html {%?extends?"layout.html"?%} {%?block?css?%} {%?endblock?%} {%?block?content?%} ????<h1>二级联动</h1> ????<select?id="province"> ????????<option?value="-1">请选择省份</option> ????????{%?for?p?in?pro_list?%} ????????????<option?value="{{?p.id?}}">{{?p.name?}}</option> ????????{%?endfor?%} ????</select> ????<select?id="city"> ????????<option?value="-1">请选择市</option> ????</select> {%?endblock?%} {%?block?js?%} ????<script> ????????$(function?()?{ ????????????bindProvinceEvent(); ????????}); ????????function?bindProvinceEvent(){ ????????????$('#province').change(function?()?{ ????????????????var?v?=?$(this).val(); ????????????????if(v?==?'-1'){ ????????????????}else{ ????????????????????$('#city?option:gt(0)').remove(); ????????????????????$.ajax({ ????????????????????????url:?'/fetch_city.html',????????????????????????type:?'GET',????????????????????????data:?{'province_id':?v},????????????????????????dataType:?'json',????????????????????????success:?function?(arg)?{ ????????????????????????????$.each(arg,?function(k,v){ ????????????????????????????????var?city_id?=??v.pk; ????????????????????????????????var?city_name?=?v.fields.name; ????????????????????????????????var?tag?=?document.createElement('option'); ????????????????????????????????tag.innerHTML?=?city_name; ????????????????????????????????tag.setAttribute('value',?city_id); ????????????????????????????????$('#city').append(tag); ????????????????????????????}); ????????????????????????} ????????????????????}) ????????????????} ????????????}) ????????} ????</script> {%?endblock?%} 三、高级操作 3.1.F() 表达式 一个 F()对象代表了一个model的字段值或注释列。使用它就可以直接参考model的field和执行数据库操作而不用再把它们(model field)查询出来放到python内存中。作为代替,Django使用 F()对象生成一个SQL表达式,来描述数据库层级所需要的操作 from?django.db.models?import?F reporter?=?Reporters.objects.get(name='Tintin') reporter.stories_filed?=?F('stories_filed')?+?1 reporter.save() 虽然reporter.stories_filed = F('stories_filed') + 1看起来像一个正常的Python分配值赋给一个实例属性,事实上这是一个描述数据库操作的SQL概念 当Django遇到 F()实例,它覆盖了标准的Python运算符创建一个封装的SQL表达式。在这个例子中,reporter.stories_filed就代表了一个指示数据库对该字段进行增量的命令。 无论reporter.stories_filed的值是或曾是什么,Python一无所知--这完全是由数据库去处理的。所有的Python,通过Django的F() 类,只是去创建SQL语法参考字段和描述操作。 F()配合 update()可以应用于对象实例的 QuerySets这减少了我们上面使用的两个查询 - get()和save() - 只有一个: reporter?=?Reporters.objects.filter(name='Tintin') reporter.update(stories_filed=F('stories_filed')?+?1) 我们可以使用update()方法批量地增加多个对象的字段值。这比先从数据库查询后,通过循环一个个增加,并一个个保存要快的很多。 Reporter.objects.all().update(stories_filed=F('stories_filed')?+?1) F()表达式的效率上的优点主要体现在:直接通过数据库操作而不是Python;减少数据库查询次数。 3.2.Q() 对象 Q() 对象和F 对象类似,把一个SQL 表达式封装在Python 对象中,这个对象可以用于数据库相关的操作。 通常,Q() 对象使得定义查询条件然后重用成为可能。这允许construction of complex database queries使用| (OR) 和 & (AND) 操作符; 否则QuerySets中使用不了OR。 例如,下面的Q 对象封装一个LIKE 查询: from?django.db.models?import?Q Q(question__startswith='What') Q 对象可以使用& 和| 操作符组合起来。当一个操作符在两个Q 对象上使用时,它产生一个新的Q 对象。 例如,下面的语句产生一个Q 对象,表示两个"question__startswith" 查询的“OR” : Q(question__startswith='Who')?|?Q(question__startswith='What') 它等同于下面的SQL WHERE 子句: WHERE?question?LIKE?'Who%'?OR?question?LIKE?'What%' 你可以组合& 和| 操作符以及使用括号进行分组来编写任意复杂的Q 对象。同时,Q 对象可以使用~ 操作符取反,这允许组合正常的查询和取反(NOT) 查询: Q(question__startswith='Who')?|?~Q(pub_date__year=2005) 每个接受关键字参数的查询函数(例如filter()、exclude()、get())都可以传递一个或多个Q 对象作为位置(不带名的)参数。如果一个查询函数有多个Q 对象参数,这些参数的逻辑关系为“AND"。例如: Poll.objects.get( Q(question__startswith='Who'), Q(pub_date=date(2005,?5,?2))?|?Q(pub_date=date(2005,?6)) ) 大体上可以翻译成这个SQL: SELECT?*?from?polls?WHERE?question?LIKE?'Who%'AND?(pub_date?=?'2005-05-02'?OR?pub_date?=?'2005-05-06') 3.3.执行原生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()?#?cursor.fetchall() ?3.4 extra 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"},),?order_by=['-nid']) 3.5 其他 def?select_related(self,?*fields) ????性能相关:表之间进行join连表操作,一次性获取关联的数据。 ????model.tb.objects.all().select_related() ????model.tb.objects.all().select_related('外键字段') ????model.tb.objects.all().select_related('外键字段__外键字段') ????主动做连表操作 ????select?*?from?user?left?join?user_type?on?tb.xxx=tb1.oo??????????????? ????? def?prefetch_related(self,?*lookups) ????性能相关:多表连表操作时速度会慢,使用其执行多次SQL查询在Python代码中实现连表操作。 ????????????#?获取所有用户表 ????????????#?获取用户类型表where?id?in?(用户表中的查到的所有用户ID) ????????????#select?*?from?user_type?where?id?in?用户类型ID{1,2} ????????????models.UserInfo.objects.prefetch_related('外键字段')??????#不连表,一次性多次查询 def?annotate(self,?*args,?**kwargs) ????#?用于实现聚合group?by查询 #?用于实现聚合group?by查询????前面的values写的是谁,就group谁 ????from?django.db.models?import?Count,?Avg,?Sum ????v?=?models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')) ???? ????print(v.query) ????#?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 ????from?django.db.models?import?Count,?Case,?When,?IntegerField ????Article.objects.annotate( ????????numviews=Count(Case( ????????????When(readership__what_time__lt=threshold,?then=1),????????????output_field=CharField(),????????)) ????) ????students?=?Student.objects.all().annotate(num_excused_absences=models.Sum( ????????models.Case( ????????????models.When(absence__type='Excused',????????default=0,????????output_field=models.IntegerField() ????)))???????? def?aggregate(self,?**kwargs): ???#?聚合函数,获取字典类型聚合结果 ???from?django.db.models?import?Count,?Sum result?=?models.UserInfo.objects.aggregate(k=Count(n=Count('nid')) {‘n’:4} result?=?models.UserInfo.objects.aggregate(k=Count(n=Count('nid'),distinct=True) 去重后的数目 result?=?models.UserInfo.objects.aggregate(k=Count('u_id',?distinct=True),?n=Count('nid')) ===>?{'k':?3,?'n':?4} 常用方法 def?all(self)????#?获取所有的数据对象def?filter(self,?**kwargs)????#?条件查询 ????#?条件可以是:参数,字典,Qdef?exclude(self,?**kwargs)????#?条件查询 ????#?条件可以是:参数,字典,Qdef?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"},)) ????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"},?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,?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,?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',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?count(self):???#?获取个数def?get(self,?**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':?'2222211','u_id':?2,?'t_id':?2})def?update_or_create(self,?**kwargs):????#?如果存在,则更新,否则,创建 ????#?defaults?指定创建时或更新时的其他字段 ????obj,?created?=?models.UserInfo.objects.update_or_create(username='root1',?'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)#等于models.DDD.objects.filter(id__in=id_list)def?delete(self):???#?删除def?update(self,?**kwargs):????#?更新def?exists(self):???#?是否有结果 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |