./queries.md
- 启动的时候不会链接数据库
- 执行shell和command也不会自动链接
- 查看查询的SQL语句
from django.db import connection
print connection.queries
objs = model.objects.filter(status=1).update(status=1)
- Filters can reference fields on the model
from django.db.models import F
Entry.objects.filter(number_of_comments__gt=F('number_of_pingbacks'))
Entry.objects.filter(number_of_comments__gt=F('number_of_pingbacks') * 2)
Entry.objects.filter(rating__lt=F('number_of_comments') + F('number_of_pingbacks'))
Entry.objects.filter(authors__name=F('blog__name'))
from datetime import timedelta
Entry.objects.filter(mod_date__gt=F('pub_date') + timedelta(days=3)) 找到发布3天后,仍然被修改的书籍
- The pk lookup shortcut
from django.contrib.admin.utils import NestedObjects
nested_object = NestedObjects("default")
nested_object.collect([Item])
print(nested_object.nested())
一些基础的知识,创建数据,删除数据等等
-
用
foreignkey__id__gte
并不会导致额外的join,而是直接用foreignkey_id
来排序对比了 -
例子django会把没有的字段当作None来处理。所以:
Search.objects.filter(user__username='wx') # left join式的过滤。如果没有user,也会被过滤掉
Search.objects.exclude(user__username='wx') # 如果没有user,也不会过滤掉
TestQuery.objects.exclude(user__id=4001) # 会搜索出user为None的
TestQuery.objects.filter(user__id=None) # 会搜索出user为None的
# user都没有,更没有id,id更不可能属于这个列表
TestQuery.objects.filter(user__id__in=[4001]) # 不会搜索出user为None的
# exclude并不没有user__id必须存在这个前提条件
TestQuery.objects.exclude(user__id__in=[4001]) # 会搜索出user为None的
Blog.objects.filter(entry__authors__name='Lennon') # 如果author不存在的Blog不会返回
Blog.objects.filter(entry__authors__name__isnull=True) # 这时候author不存在的也会返回
Blog.objects.filter(entry__authors__isnull=False, entry__authors__name__isnull=True) # 这样就能指定必须含有authors,并且authors为空
- 多字段查询关联的歧义
User.objects.filter(shop__title__contains='shop', shop__gmt_create__year=2008) # 于2008年注册过商店名包含'shop'的所有用户
User.objects.filter(shop__title__contains='shop').filter(shop__gmt_create__year=2008) # 商店名有shop,并且于2008年注册过商店的用户
User.objects.exclude(shop__title__contains='shop', shop__id=3) # 过滤到有店id是3并且名字有shop的用户
User.objects.exclude(shop__title__contains='shop', shop__name__contains='ew') # 过滤所有title包含shop和name包含ew的
User.objects.exclude(shop = Shop.objects.filter(location__contains='tian', name__contains='test')) # 用户
ClassRoom.objects.filter(student__name__contains='王') # 找到包含名字有王学生的的班级
# 但是如果有两个人都包含"王",那这个班级就会出现两次,所以用distinct()
Blog.objects.filter(entry__authors__name__isnull=True)
- 如果是exclude的话会怎么样(暂时没遇到这个需求,以后再说)
- django的各种查询语句: filter, exclude, annotate等
- django的各种过滤方法: in, exact, contains等
- annotate
- order_by 直接按照字段排序
Entry.objects.order_by("-pub_date", "headline") # 直接按照字段排序
Entry.objects.order_by("?") # 随机排序
Entry.objects.order_by("blog__name", "headline") # 按照外键排序
ManyModel.objects.annotate(text_id=Min("texts__id")).order_by("text_id") # 按照ManyToMany的表的某个字段排序
- reverse
- distinct
- values
TestFilterModel2.objects.values('_bool', '_int').annotate(Count('id')) # 利用_bool, _int进行分组,查看数量
MingpianChange.objects.order_by("amount").values("amount").annotate(Count("id")) # 查看各个amount对应的数量
官网
values_list(*fields, flat=False, named=False)
原理是通过select只看部分字段, 所以遇到外键是会有None, 遇到ManyToMany时数据会重复
named可以返回django.db.models.utils.Row
, 直接获取属性
Entry.objects.values("id", flat=True)
<Queryset [1, 2]> 可以继续过滤, 也可以直接迭代得到1, 2
- defer
Entry.objects.defer("body")
: only access the body field when you use thebody
field to optimize the performance
用来给行加锁, 这样其他函数调用时会卡在那。
# 线程1
from django.db import transaction
with transaction.atomic():
entry = Entry.objects.select_for_update(nowait=True).filter(status="inactive").first()
entry.status = "active"
entry.save()
# 线程2
Entry.objects.get(id=1) # 这句卡住,直到上面status改了save了
get, create, get_or_create
get_or_create
:
Model.objects.get_or_create(text='w') # 如果是创建的话会调用save函数
obj, created = <model>.objects.get_or_create(user__name='wangx')
# 不存在用户就不登录而是注册
# created 为 True, 代表了obj是新建
# 如果返回多条数据,会报错的
# 创建的时候的时候会自动保存, 但是要注意, 如果有写field不允许null, 就需要get的时候把参数传进去
# get_or_create里面如果传递的是过滤参数,就会先用过滤参数过来
obj, created = <model>.objects.get_or_create(text='text', time__gt='2017-12-12T10:24:00+08:00')
update_or_create(defaults=None, **kwargs)
通过kwargs来查找数据. 如果没有就创建- bulk_create: 一次性创建多个instance
- 如果某个创建失败了,会导致之后的也创建失败, 类似事务
- 如果把foreignkey的对象传进去,不会校验,而是直接读取pk属性
- 不会触发signal信号,但是auto_now的属性会变化并且各个model不一致
- 保存完毕后, 对象里面会自动存在id
Shop.objects.bulk_create([
Shop(user=user, name='test'),
Shop(user=user, name='test2')])
])
- exact
- iexact
- contains
- icontains
- startswith
When
USE_TZ
is True, fields are converted to the current time zone before filtering.
Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
But the date is filtered by the date of server timezone. What if you want to filter the date create by customer living in other timezone district? I find the only way is to use time range.
* 这个date过滤还直接输入一个时间来过滤。这个时候会先把datetime转化成local的时间,然后再取date过滤
```
Entry.objects.filter(pub_date__date=datetime)
```
- Example
from django.db.models import Count, F, Value from django.db.models.functions import Length, Upper # Find companies that have more employees than chairs. 找到职工比凳子多的公司 # F 把表的某个值当作判断 Company.objects.filter(num_employees__gt=F('num_chairs')) # Find companies that have at least twice as many employees # as chairs. Both the querysets below are equivalent. # 找到员工数比椅子两倍还多的公司 Company.objects.filter(num_employees__gt=F('num_chairs') * 2) Company.objects.filter( num_employees__gt=F('num_chairs') + F('num_chairs')) # How many chairs are needed for each company to seat all employees? # 添加每个公司还需要多少椅子的信息 >>> company = Company.objects.filter( ... num_employees__gt=F('num_chairs')).annotate( ... chairs_needed=F('num_employees') - F('num_chairs')).first() >>> company.num_employees 120 >>> company.num_chairs 50 >>> company.chairs_needed 70 # Create a new company using expressions. >>> company = Company.objects.create(name='Google', ticker=Upper(Value('goog'))) # Be sure to refresh it if you need to access the field. >>> company.refresh_from_db() >>> company.ticker 'GOOG' # Annotate models with an aggregated value. Both forms # below are equivalent. Company.objects.annotate(num_products=Count('products')) Company.objects.annotate(num_products=Count(F('products'))) # Aggregates can contain complex computations also Company.objects.annotate(num_offerings=Count(F('products') + F('services'))) # Expressions can also be used in order_by() Company.objects.order_by(Length('name').asc()) Company.objects.order_by(Length('name').desc())
- Build-in Expressions
用这个以后可以使用 |(or), &(and), ^(XOR), ~(NOT)操作
from django.db.models import Q
q1 = Q(name0="name0") | Q(name1="name1") & Q(name2="name2")
q2 = Q(name0="name0") | Q(name1="name1")
q2 &= Q(name2="name2")
注意,因为一句一句执行,所以q2的顺序和q1不一样. q1因为执行顺序的原因,先执行&
比较高端,暂时没用过
groupby无法group后对每个group都选指定的最新的数据。直接用多重select可能性能不咋地
Travel.objects.values('interest2').annotate(Count('user', distinct=True))
# 对所有的旅行记录排序,看看那个经典(去的人次/去过的人, 有distinct就是一个人只能算去一次)最多
Book.objects.values('name').annotate(Count('id')).order_by()
# group the book by its name, order_by is required or the the group will not have effect.
GetOrCreateModel.objects.annotate(date=TruncDate('time')).values('date').annotate(Count('id'))