Django字段查找(Field lookups) | 您所在的位置:网站首页 › django查询指定字段的值 › Django字段查找(Field lookups) |
在Django中ORM访问数据库查找时,会用到一些带双下划线的操作,类似Entry.objects.filter(id__gt=4)这种。 本文记录了双下划线之后的“方法”的作用和用法。 学习了下官方文档,在这里总结记录下。若有不清晰的,可参考官方文档:Django2.1官方文档 目录 exact iexact contains icontains in gt gte lt lte startswith istartswith endswith iendswith range date year month day week week_day quarter(Django2.0新增) time hour minute second isnull regex iregex 字段查找是指定SQL WHERE子句的内容的方式,他们用在filter(),exclude()和get()这些QuerySet方法。 Django的内置查找如下,也可以编写自定义查找。 exact为了方便起见,当没有提供查找类型时(比如 Entry.objects.get(id=12) ),查找类型就假定为exact。 精确匹配。如果为匹配提供的值是None,则会被解读为SQL中的NULL值,例如: Entry.objects.get(id__exact=12) Entry.objects.get(id__exact=None)相当于SQL语句: SELECT ... WHERE id = 12; SELECT ... WHERE id IS NULL; MySQL 匹配在MySQL中,数据库表的名为“collation”的设置来确定exact匹配是否区分大小写。 这是一个数据库设置,而不是Django设置。 可以将MySQL表配置为区分大小写,但需要进行一些权衡。 有关这方面的更多信息,查看Collation settings。 iexact不区分大小写的精确匹配。例如: Blog.objects.get(name__iexact='beatles blog') Blog.objects.get(name__iexact=None)相当于SQL语句: SELECT ... WHERE name ILIKE 'beatles blog'; SELECT ... WHERE name IS NULL;'Beatles Blog', 'beatles blog', 'BeAtLes BLog'等等都会被上面第一个查询匹配到。 contains区分大小写的包含匹配。例如: Entry.objects.get(headline__contains='Lennon')相当于SQL语句: SELECT ... WHERE headline LIKE '%Lennon%';这会匹配到‘Lennon honored today’但是不会匹配到‘lennon honored today’。(因为区分大小写) SQLlite 用户SQLite不支持区分大小写的 “LIKE”声明,所以对于SQLite来说,contains和icontains是一样的。 icontains不区分大小写的包含匹配。使用方法见contains。 in在一个给定的可迭代对象中,通常是一个列表,元组,或queryset,它并不常用,但是接受字符串(可迭代)。例如: Entry.objects.filter(id__in=[1, 3, 4]) Entry.objects.filter(headline__in='abc')相当于SQL语句: SELECT ... WHERE id IN (1, 3, 4); SELECT ... WHERE headline IN ('a', 'b', 'c');如果在in操作中传入values()或者value_list()的queryset结果,必须确保这个结果只提取了一个字段。例如: # 正确操作,只提取了一个“name” inner_qs = Blog.objects.filter(name__contains='Ch').values('name') entries = Entry.objects.filter(blog__name__in=inner_qs) # 错误操作,提取了“name”和“id”两个字段,会抛出TypeError inner_qs = Blog.objects.filter(name__contains='Ch').values('name', 'id') entries = Entry.objects.filter(blog__name__in=inner_qs) 性能考虑:请谨慎使用嵌套查询并了解数据库服务器的性能特征(如果有疑问,请使用基准测试!)。一些数据库后端,尤其是MySQL,不能很好地优化嵌套查询。在这些情况下,提取值列表然后将其传递到第二个查询更有效。也就是说,执行两个查询而不是一个: values = Blog.objects.filter( name__contains='Cheddar').values_list('pk', flat=True) entries = Entry.objects.filter(blog__in=list(values))注意:list()会强制执行第一个查询,没有它,会变成嵌套查询,因为QuerySet是懒惰的。 gtGreater than. (大于) 例如: Entry.objects.filter(id__gt=4) # 即 SELECT ... WHERE id > 4; gteGreater than or eaual to.(大于等于) ltLess than. (小于) lteLess than or equal to. (小于等于) startswith以。。。开头(区分大小写) istartswith以。。。开头(不区分大小写) endswith以。。。结尾(区分大小写) iendswith以。。。结尾(不区分大小写) range范围过滤(包含边界)。例如: import datetime start_date = datetime.date(2005, 1, 1) end_date = datetime.date(2005, 3, 31) Entry.objects.filter(pub_date__range=(start_date, end_date)) # 相当于SQL SELECT ... WHERE pun_date BETWEEN '2005-01-01' and '2005-03-31';只要在SQL中能使用BETWEEN的地方,都能使用range——对时间,数字,甚至字符。 Warning!Filter一个DateTimeField字段会不包括时间范围的最后一天,因为界限被解析为“给定日期的0点”,如果pub_date是一个DateTImeField类型,上面的Python代码翻译成SQL会是: SELECT ... WHERE pub_date BETWEEN '2005-01-01 00:00:00' and '2005-03-31 00:00:00';也就是说,不能混用date和datetime,他们有差别。 date将datetime类型的字段转换为date,允许链接其他字段查找,得到一个date类型的值。例如: Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1)) Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))(此查找不包含等效的SQL代码片段,因为相关查询的实现因不同的数据库引擎而异。) 当USE_TZ为True时,字段将在筛选之前转换为当前时区。 year对于date和datetime字段,精确地匹配年份。允许链接其他字段查找,筛选时传入一个int型年份。例如: Entry.objects.filter(pub_date__year=2005) Entry.objects.filter(pub_date__year__gte=2005) # 相当于SQL SELECT ... WHERE pub_date BETWEEN '2005-01-01' AND '2005-12-31'; SELECT ... WHERE pub_date >= '2005-01-01';(具体的SQL语法取决于具体的数据库引擎。) 当USE_TZ为True时,字段将在筛选之前转换为当前时区。 month和year作用相同,筛选时传入一个int型月份(1-12)。 Entry.objects.filter(pub_date__month=12) Entry.objects.filter(pub_date__month__gte=6) # 相当于SQL SELECT ... WHERE EXTRACT('month' FROM pub_date) = '12'; SELECT ... WHERE EXTRACT('month' FROM pub_date) >= '6'; day和year以及month作用相同。 Entry.objects.filter(pub_date__day=3)会筛选出来若干条日期为3的记录,例如一月三号,二月三号等等。 week对于date和datetime字段,返回周数(1-52 or 53)。 Entry.objects.filter(pub_date__week=52)会筛选出日期为一年中第52周的记录。 week_day对于date和datetime字段作一个“一周中的哪一天”匹配。 筛选时传入一个int型值代表星期几(1-7, 1代表Sunday,7代表Saturday)。 Entry.objects.filter(pub_date__week_day=2) 这会筛选出所有当天日期是星期一的记录,和月份年份都无关。 quarter(Django2.0新增)对于date和datetime字段,匹配季度(1-4)。 Entry.objects.filter(pub_date__quarter=2),日期在第二个季度(4月1日至6月30日)的所有记录。 time将datetime字段转换为time,筛选时传入一个datetime.time值。例如: # 筛选时间为14:30的记录 Entry.objects.filter(pub_date__time=datetime.time(14, 30)) # 筛选时间在8:00到17:00的记录 Entry.objects.filter(pub_date__time__range=(datetime.time(8), datetime.time(17))) hour对于datetime和time字段,匹配具体的“时”,筛选时传入一个int型数字(0-23)。 minute对于datetime和time字段,匹配具体的“时”,筛选时传入一个int型数字(0-59)。 second对于datetime和time字段,匹配具体的“秒”,筛选时传入一个int型数字(0-59)。 isnullTrue或False,分别对应于IS NULL和IS NOT NULL的SQL查询。 regex区分大小写的正则表达式匹配。 正则表达式的语法取决于正在使用的数据库,例如SQLite,它没有内置的正则表达式支持,这个功能就有用户定义的REGEXP函数提供,并且正则表达式语法和Python的re模块相同。例如: Entry.objects.get(title__regex=r'^(An?|The) +') # 对应SQL SELECT ... WHERE title REGEXP BINARY '^(An?|The) +'; # MySQL SELECT ... WHERE REGEXP_LIKE(title, '^(An?|The) +', 'c'); # Oracle SELECT ... WHERE title ~ '^(An?|The) +'; # PostgreSQL SELECT ... WHERE title REGEXP '^(An?|The) +'; # SQLite iregex不区分大小写的正则表达式匹配。 以上。 |
CopyRight 2018-2019 实验室设备网 版权所有 |