Diango教程-如何使用 F() 表达式
在本教程中,我们将学习查询表达式、F 表达式以及如何在 QuerySet 中使用它。让我们对查询表达式进行简要介绍。
什么是查询表达式?
查询表达式表示可以作为更新、创建、过滤、排序、注释或聚合的一部分的值或计算。如果表达式以布尔值返回输出,则可以直接用于过滤器中。Django 提供了许多内置表达式,帮助我们编写查询。查询表达式可以嵌套或组合。
F() 表达式
F() 对象指定了模型字段的值,或者直接引用数据库中的模型字段值。让我们来看一个简单的例子,一个名为Student的类有一个fees字段,我们想要增加学生20%的费用。
可以使用如下代码完成:
student = Student.objects.all()
for stu in student:
stu.fees *= 1.2
我们可以使用F() 表达式在单个查询中完成这个操作:
from django.db.models import F
Student.objects.update(fees=F('fees') * 1.2)
我们也可以使用以下方法:
student = Student.objects.get(pk=1)
student.price = F('fees') * 1.2
student.save()
但是要小心使用这种赋值方式,F() 对象在保存模型后会保留。
student.fees # fees = Decimal('10.00')
student.fees = F('fees') + 1
student.save() # fees = Decimal('11.00')
student.name = 'What the F()'
student.save() # fees = Decimal('12.00')
在字段更新后,该字段将包含django.db.models.expression.CombinedExpression的实例,而不是实际结果。我们可以按以下方式立即访问结果:
student.fees= F('fees') + 1
product.save()
print(student.fees) # <CombinedExpression: F(price) + Value(1)>
product.refresh_from_db()
print(student.fees)
我们也可以使用数据的注释。
from django.db.models import ExpressionWrapper, DecimalField
Product.objects.all().annotate(
value_in_stock=ExpressionWrapper(
F('fees') * F('rollno'), output_field=DecimalField()
)
)
由于fees是DecimalField,而rollno是IntergerField,我们需要将表达式包装在ExpressionWrapper对象中。
F() 表达式也可用于过滤数据。
Student.objects.filter(fees__gte=F(2000))
F() 表达式可以提供以下优势:
- 帮助我们通过数据库获取数据,并限制Python访问数据库的方式。
- 帮助减少特定操作的查询次数。
使用F() 避免竞态条件。
F() 表达式还提供其他功能,例如更新字段的值可以避免竞态条件。
让我们更好地理解它——如果两个Python线程执行该代码,其中一个线程在另一个线程从数据库中检索数据之后,检索、增加并保存字段的值。该线程保存的值将基于原始值。第一个线程的过程将被使用。
每次涉及更新字段的数据库操作,该过程都会变得更加稳健。F() 表达式将根据在执行save()或update()时数据库中字段的值来更新该字段。
使用F() 对空值进行排序
我们可以使用F() 以及nulls_first或nulls_last关键字参数来对空值进行排序,从而控制字段空值的排序顺序。
让我们看下面的示例,对于新学期后尚未缴费的学生进行排序。
from django.db.models import F
Student.objects.order_by(F('fees_paid').desc(nulls_last=True))
Func() 表达式
Func() 表达式涉及数据库函数,例如COALESCE和LOWER,或者聚合函数如SUM。我们可以直接使用它们。
例如:
from django.db.models import F, Func
queryset.annotate(field_lower=Func(F('field'), function='LOWER'))
聚合表达式
聚合表达式是Func() 表达式的重要组成部分。它通知查询需要GROUP BY子句。所有聚合函数都继承自Aggregate()。
例如:
from django.db.models import Count
Student.objects.annotate(
managers_required=(Count('num_employees') /8 ) + Count('num_managers'))
Value() 表达式
Value() 对象表示表达式的最小组件。我们可以使用Value() 表达式在表达式中表示整数、布尔或字符串值。
Value() 表达式很少直接使用。当我们编写表达式F('field') + 1时,Django会隐式地将1包装在Value() 中,允许在更复杂的表达式中使用简单的值。
value参数会自动将值包含在表达式中,这些值可以是1、True或None。Django会将这些Python值转换为相应的数据库类型。output_field参数必须是模型字段实例,例如IntegerField()或BooleanField()。