from django.db.models import Count, F, Value
from django.db.models.functions import Length, Upper
F表达式的一般用法
# 找到员工比椅子多的公司。
Company.objects.filter(num_employees__gt=F('num_chairs'))
# 找到雇员至少是原来两倍的公司,下面的两个查询集的执行结果是等效的。
Company.objects.filter(num_employees__gt=F('num_chairs') * 2)
Company.objects.filter(
num_employees__gt=F('num_chairs') + F('num_chairs'))
F表达式的组合用法
# 每个公司需要多少张椅子来容纳所有的员工?
>>> 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
Upper表达式的用法
# 使用 Upper 的表达式创建一个公司记录。
>>> company = Company.objects.create(name='Google', ticker=Upper(Value('goog')))
# 如果需要访问字段,请确保刷新它。
>>> company.refresh_from_db()
>>> company.ticker
'GOOG'
聚合与F的配合使用
- 用 Annotate 模型方法以及 经过聚合方法 aggregated 得出的值构成一个新的字段别名,如下两段代码是等效的
Company.objects.annotate(num_products=Count('products'))
Company.objects.annotate(num_products=Count(F('products')))
- Aggregates 还可以包含复杂的计算
Company.objects.annotate(num_offerings=Count(F('products') + F('services')))
- 表达式也可以直接在order_by()中使用
Company.objects.order_by(Length('name').asc())
Company.objects.order_by(Length('name').desc())
- 使用双下划线查找语法。
from django.db.models import CharField
from django.db.models.functions import Length
CharField.register_lookup(Length)
Company.objects.order_by('name__length')
F表达式的一些理论
- 在这里,我们拉出了reporter的值。stories_field从数据库进入内存,使用熟悉的Python操作符对其进行操作,然后将对象保存回数据库。男人装杂志 新增一篇新闻报道
reporter = Reporters.objects.get(name='男人装')
reporter.stories_filed += 1
reporter.save()
- 通过reporter.stories_filed = F(‘stories_filed’) + 1看起来像一个普通的Python赋值给实例属性,实际上它是一个描述数据库操作的SQL构造。
- 当Django遇到F()的实例时,它会覆盖标准Python操作符来创建一个封装的SQL表达式;在本例中,它指示数据库增加reporter. stories_field所表示的数据库字段。
- 不管reporter.stories_filed的值是什么。 Python永远不会知道它是完全由数据库处理。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 = Reporters.objects.get(pk=reporter.pk)
# 更简洁的方式 更简洁
reporter.refresh_from_db()
- 除了在上面的单个实例上的操作中使用外,还可以在对象实例的查询集上使用F(),并使用update()。这将我们在上面使用的两个查询——get()和save()——减少为一个
reporter = Reporters.objects.filter(name='Tintin')
reporter.update(stories_filed=F('stories_filed') + 1)
- 我们还可以使用update()来增加多个对象的字段值——这比将它们从数据库中全部放入Python、遍历它们、增加每个对象的字段值并将每个对象保存回数据库要快得多
Reporter.objects.all().update(stories_filed=F('stories_filed') + 1)