Django F()表达式
Django F()表达式
一个F()对象代表一个模型字段的值或注释列。使用它可以直接引用模型字段的值并执行数据库操作而不用把它们导入到python的内存中。
相反,Django使用F()对象生成一个描述数据库级别所需操作的SQL表达式。
通过一个例子很容易理解。通常,有人会这样做:
reporter = Reporters.objects.get(name='Tintin')
reporter.stories_field += 1
reporter.save()
这里我们从数据库中取出reporter.stories_field的值放入内存中并使用我们熟悉的python运算符操作它,然后把对象保存到数据库中。但是我们还可以这样做:
from django.db.models import F
reporter = Reporters.objects.get(name='Tintin')
reporter.stories_field = F('stories_field') + 1
reporter.save()
虽然reporter.stories_field = F('stories_field') + 1看起来像常规的Python为实例属性赋值,但实际上它是一个描述数据库上操作的SQL结构。
当Django遇到要给F()实例,它会覆盖标准的Python运算符来创建一个封装的SQL表达式;在这个例子中,指示数据库增加由reorter.stories_field表示的数据库字段。
无论repoter.stories_field的值是或曾是什么,Python永远不需要知道--完全由数据库来处理。Python通过Django的F()类做的所有事情仅是参考某个字段创建SQL语法来描述操作。
实例对象必须重新加载后才能获取以这种方式保存的值:
reporter = Reporters.objects.get(pk=reporter.pk)
# 或者,更简洁的操作
reporter.refresh_from_db()
像上面这样在单个实例中使用,F()可以通过updage()方法被用在QuerySets对象实例中。这样可以省略上面用到的两个查询--get()和save():
reporter = Reporters.objects.filter(name='Tintin')
reporter.update(stories_field=F('stories_field') + 1)
我们也可以使用update()来增加多个对象的字段值,这样比从数据中取出他们,通过循环挨个增加值,然后再保存回数据库中要更加快速:
Reporters.objects.all().update(stories_field=F('stories_field') + 1)
因此,F()可以通过以下方式提供性能优势:
- 直接在数据库中操作而不是python
- 减少一些操作所需的数据库查询次数
使用F()避免竞争关系
使用F()的另一个好处是使用数据库来更新字段而不是用Python,以此避免竞争关系。
如果有两个Python线程执行上面第一个示例,A线程可能在B线程从数据库检索数据后来检索、增加并保存某个字段值。那么B线程的保存将基于他最初检索到的原始值;而A线程的工作将会丢失。
如果有数据库自身负责更新字段,这个过程将会更加健壮:在执行sasve()和update()时基于数据库中当前的字段值,而不是基于被检索出的实例的值。
F()操作在Model.save()后会持续存在
分配给模型字段的F()对象在模型实例保存后依然保持不变,并会应用于之后的每个save()。例如:
reporter = Reporters.objects.get(name='Tintin')
reporter.stories_field = F('stories_field') + 1
reporter.save() # F()表达式第一次执行
reporter.name = 'Tintin Jr')
reporter.save() # F()表达式第二次执行
stories_field将会被更新两次!如果初始值为1,那么最终值将会是3
在过滤器(filter)中使用F()
F()在QuerySet过滤器中也非常有用,通过它可以实现基于自身字段值来过滤一组对象,而不是通过Python值。
F()实例充当查询中一个模型字段的引用。这些引用在查询过滤器可以被用来比较同一模型实例的两个不同字段的值。
例如,我们要查找所有Blog记录中comment多于pingback的记录,我们构建一个F()对象来引用pingback的数量:
"""
class Entry(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
headline = models.CharField(max_length=255)
body_text = models.TextField()
pub_date = models.DateField()
mod_date = models.DateField()
authors = models.ManyToManyField(Author)
n_comments = models.IntegerField()
n_pingbacks = models.IntegerField()
rating = models.IntegerField()
def __str__(self):
return self.headline
"""
from django.db.models import F
Entry.objects.filter(n_commnets__gt=F('n_pingbacks'))
Django支持F()对象使用加、减、乘、除、取模和幂运算等算术操作,两个操作数可以是常数或F()对象。要查询blog记录中comment大于两本pingback的记录,修改查询为:
Entry.objects.filter(n_comments__gt=F('n_pingbacks') * 2)
为了查询rating 比pingback 和comment 数目总和要小的记录,我们将这样查询:
Entry.objects.filter(rating__lt=F('n_comments') + F('n_pingbacks'))
你还可以在F() 对象中使用双下划线标记来跨越关联关系。 带有双下划线的F() 对象将引入任何需要的join 操作以访问关联的对象。 例如,如要获取author 的名字与blog 名字相同的Entry,我们可以这样查询:
Entry.objects.filter(authors__name=F('blog__name'))
对于date 和date/time 字段,你可以给它们加上或减去一个timedelta对象。 下面的例子将返回发布超过3天后被修改的所有Entry:
from datetime import timedelta
Entry.objects.filter(mod_date__gt=F('pub_date') + timedelta(days=3))
在annotate中使用F()
F()可以使用算术运算组合不同字段在模型中创建动态字段。
company = Company.objects.annotate(chairs_needed=F('num_employee') - F('num_chairs'))
如果组合的是不同类型的字段,你需要告诉Django返回值是哪种字段类型。由于F()不直接支持output_field,所以需要使用ExpressionWrapper来封装表达式:
from django.db.models import DatetimeField, ExpressionWrapper, F
Ticket.objects.annotate(
expires=ExpressionWrapper(
F('active_at') + F('duration'), output_field=DateTimeField()
)
)
当引用关联字段(如ForeignKey)时,F()返回的主键值而不是一个模型实例:
>>> car = Company.objects.annotate(built_by=F('manufacturrer'))[0]
>>> car.manufacturer
<Manufacturer: Toyota>
>>> car.built_by
3
使用F()对null值排序
使用F()和传递nulls_first或nulls_last参数给Expression.asc()或desc()来控制字段的null值的排序。默认情况下这个排序取决于你的数据库。
例如,要将未联系过(last_contacted为null)的公司排在已联系过的公司后面:
from django.db.models import F
Company.objects.order_by(F('last_contacted').desc(nulls_last=True))
翻译自Django文档
Django F()表达式的更多相关文章
- django F表达式、Q表达式、annotate、order_by
如下模型: class Book(models.Model): name = models.CharField(max_length=100) pages = models.IntegerField( ...
- Django运算表达式与Q对象/F对象
Django运算表达式与Q对象/F对象 1 模型查询 概述: 1 查询集:表示从数据库中获取的对象的集合 2 查询集可以有多个过滤器,通过 逻辑运算符连接 3 过滤器就是一个函数,基于所给的参数限制查 ...
- django orm高级查询 F表达式和Q表达式以及分组annotate
1.关联关系映射及查询1.1django默认开启延迟加载所有多对1和1对1如果不使用select_related(),需要会延迟加载获取到相关对象,因为延迟可能会造成n+1次查询的问题,所以便有了se ...
- django2外键,F表达式,Q表达式
一对多 环境 两个类:书的类别和文章,一片文章只能有一个作者,一个作者可以有多个文章,这之间组成了一对多的关系 class Category(models.Model): category = mod ...
- 76.Python中F表达式详解
F表达式是用来优化ORM操作数据库的. 举个例子:我们做口罩的公司要将所有员工的薪水增加2000元,如果按照正常的流程,应该是先从数据库中提取所有的员工的工资到Python内存中,然后使用Python ...
- python中F/f表达式优于format()表达式
F/f表达式可以解析任意类型的数据 具体实现,看下面示例: 1.解析变量 1 a = 10 3 b = 20 5 res1 = F"a+b的值:{a+b}" 7 print(res ...
- python 格式化输出详解(占位符:%、format、f表达式)——上篇 理论篇
0 - 占位符介绍 要实现字符串的拼接,使用占位符是的一种高效.常用的方式. 举个例子,下面是不使用占位符的一种写法,直接使用加号拼接字符串 name = "Li hua" age ...
- Django运算符表达式
在html页面中,加入运算符表达式,进行逻辑判断.可参考手册.我用的Django是2.1版本 view.py中的代码: from django.shortcuts import render from ...
- Django F对象的使用
概念 class FF()是代表模型字段的值,也就是说对于一些特殊的字段的操作,我们不需要用Python把数据先取到内存中,然后操作,在存储到db中了. 场景 例1:我们有个统计点击量的字段,每次更新 ...
随机推荐
- 新加了一块硬盘,在bios中可以看的到,在系统的磁盘管理器中看不到新加硬盘
今天新加了一块硬盘,进入bios中可以看到新加的硬盘,但是进入系统后在磁盘管理及磁盘驱动器中都看不到.并且在设备管理器下其他设备出现了ATA channel1,前面显示感叹号,如下图所示: 而且电脑变 ...
- Java编程从头开始---老妪能解
思想导向: 今天想要分享的是最基础的东西就是如何写一个简单的代码,很多人都是小白,需要的其实并不是很高端的理论,框架和思维模式啊,设计方法啊,这些对于一个新人来说实在是好高骛远,说的那么高端,结果要学 ...
- classmethod,staticmethod
'''1 绑定方法: 在类内部定义的函数,默认就是给对象来用,而且是绑定给对象用的,称为对象的绑定方法 绑定对象的方法特殊之处: 应该由对象来调用,对象来调用,会自动将对象当作第一个参数传入 绑定到类 ...
- 模块import,from ..import...
首次导入模块发生3件事 1.创建一个模块的名称空间 2.执行文件spam.py,将执行过程中产生的名字都放到模块的名称空间中 3.在当前执行文件中直接拿到一个名字,该名字就是执行模块中相对应的名字 f ...
- Python爬虫防封杀方法集合
Python爬虫防封杀方法集合 mrlevo520 2016.09.01 14:20* 阅读 2263喜欢 38 Python 2.7 IDE Pycharm 5.0.3 前言 ...
- (转)Eclipse开发Web项目
1. 建立最简单的JSP和servlet http://wenku.baidu.com/link?url=bcf8iwB3E5_gjl46WfZAekQUWsps0-G3MAbbKz5totQcvmS ...
- 【python-字典】判断python字典中key是否存在的
一般有两种通用做法: 第一种方法:使用自带函数实现: 在python的字典的属性方法里面有一个has_key()方法: #生成一个字典 d = {'name':Tom, 'age':10, 'Tel' ...
- 9.DataGrid数据表格
后台获取数据并将其转换为json数组格式: 前台获取数据并显示在数据表格中:
- excel冻结窗格
编辑excel时冻结窗格可以大大增加可读性.每个sheet都应该加上. 第一份工作的时候,上司比较严格,还因为这个挨过几次骂.所以这个技巧大家一定要掌握 方法很简单: 选中首行:视图 -- 冻结窗格 ...
- cxgrid强大用法
cxgrid强大用法 (2012-07-25 14:09:42) 转载▼ 标签: delphi cxgrid 用法 强大 杂谈 分类: Delphi cxGrid功能强大,适合做企业级的复杂查询.非常 ...