一、直接生成SQL语句
需求一:使文章表中的阅读数+1
普通方法:
article.clicks += 1
article.save()
上面的方法是django首先将clicks字段查询出来,保存在内存中,然后用python的语法进行+1,然后保存数据库
F用法:
article.clicks = F('clicks') + 1
article.save()
article.refresh_from_db()
注意: 使用F用法,会直接生成对某个字段+1的SQL语句,但是需要注意的是在使用上述方法更新过数据之后需要重新加载数据来使数据库中的值与程序中的值对应:
article = Article.objects.get(pk=article.pk)
# 或者
article.refresh_from_db()
需求二:修改多条数据+1
与上面的在一个对象中操作的例子相似,F()函数同样可以使用在查询集中,配合update()方法。这样我们同样可以将更新的两步合并成一步:
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
Grade.objects.filter(boy_num__gt=F('girl_num'))
如果我们想要获取到男生比女生多10个的班级
Grade.objects.filter(boy_num=F('girl_num')+10)
三、结合annotate可用于在模型上自定义字段
F()函数可以在创建模型时根据已知的N个字段组合出另外的字段数据
并将售价(price)- 成本(cost)的查询结果命名为收入(income)
goods = Goods.objects.annotate(income=F('price')-F('cost'))
但是如果组合的两个字段拥有不同的数据类型,那么咱们需要手动告诉Django新生成的数据类似是什么,看下面的列子:
from django.db.models import DateTimeField, ExpressionWrapper, F
Ticket.objects.annotate(expires=ExpressionWrapper(F('active_at') + F('duration'), output_field=DateTimeField()))