“Django/docs/2.2.x/ref/models/expressions”的版本间差异

来自菜鸟教程
Django/docs/2.2.x/ref/models/expressions
跳转至:导航、​搜索
(autoload)
 
(Page commit)
 
第1行: 第1行:
 +
{{DISPLAYTITLE:查询表达式 — Django 文档}}
 
<div id="query-expressions" class="section">
 
<div id="query-expressions" class="section">
  
= Query Expressions =
+
= 查询表达式 =
  
Query expressions describe a value or a computation that can be used as part of
+
查询表达式描述可用作更新、创建、过滤、排序依据、注释或聚合的一部分的值或计算。 有许多内置表达式(记录如下)可用于帮助您编写查询。 表达式可以组合,或在某些情况下嵌套,以形成更复杂的计算。
an update, create, filter, order by, annotation, or aggregate. There are a
 
number of built-in expressions (documented below) that can be used to help you
 
write queries. Expressions can be combined, or in some cases nested, to form
 
more complex computations.
 
  
 
<div id="supported-arithmetic" class="section">
 
<div id="supported-arithmetic" class="section">
  
== Supported arithmetic ==
+
== 支持的算术 ==
  
Django supports negation, addition, subtraction, multiplication, division,
+
Django 支持负、加、减、乘、除、模数运算,以及对查询表达式的幂运算符,使用 Python 常量、变量,甚至其他表达式。
modulo arithmetic, and the power operator on query expressions, using Python
 
constants, variables, and even other expressions.
 
  
 
<div class="versionchanged">
 
<div class="versionchanged">
  
Support for negation was added.
+
<span class="versionmodified changed"> 2.1 版更改: </span> 添加了对否定的支持。
  
  
第27行: 第22行:
 
<div id="some-examples" class="section">
 
<div id="some-examples" class="section">
  
== Some examples ==
+
== 一些例子 ==
  
 
<div class="highlight-python notranslate">
 
<div class="highlight-python notranslate">
第33行: 第28行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>from django.db.models import Count, F, Value
+
<syntaxhighlight lang="python">from django.db.models import Count, F, Value
 
from django.db.models.functions import Length, Upper
 
from django.db.models.functions import Length, Upper
  
第46行: 第41行:
  
 
# How many chairs are needed for each company to seat all employees?
 
# How many chairs are needed for each company to seat all employees?
&gt;&gt;&gt; company = Company.objects.filter(
+
>>> company = Company.objects.filter(
 
...    num_employees__gt=F('num_chairs')).annotate(
 
...    num_employees__gt=F('num_chairs')).annotate(
 
...    chairs_needed=F('num_employees') - F('num_chairs')).first()
 
...    chairs_needed=F('num_employees') - F('num_chairs')).first()
&gt;&gt;&gt; company.num_employees
+
>>> company.num_employees
 
120
 
120
&gt;&gt;&gt; company.num_chairs
+
>>> company.num_chairs
 
50
 
50
&gt;&gt;&gt; company.chairs_needed
+
>>> company.chairs_needed
 
70
 
70
  
 
# Create a new company using expressions.
 
# Create a new company using expressions.
&gt;&gt;&gt; company = Company.objects.create(name='Google', ticker=Upper(Value('goog')))
+
>>> company = Company.objects.create(name='Google', ticker=Upper(Value('goog')))
 
# Be sure to refresh it if you need to access the field.
 
# Be sure to refresh it if you need to access the field.
&gt;&gt;&gt; company.refresh_from_db()
+
>>> company.refresh_from_db()
&gt;&gt;&gt; company.ticker
+
>>> company.ticker
 
'GOOG'
 
'GOOG'
  
第78行: 第73行:
 
from django.db.models.functions import Length
 
from django.db.models.functions import Length
 
CharField.register_lookup(Length)
 
CharField.register_lookup(Length)
Company.objects.order_by('name__length')</pre>
+
Company.objects.order_by('name__length')</syntaxhighlight>
  
 
</div>
 
</div>
第87行: 第82行:
 
<div id="built-in-expressions" class="section">
 
<div id="built-in-expressions" class="section">
  
== Built-in Expressions ==
+
== 内置表达式 ==
  
 
<div class="admonition note">
 
<div class="admonition note">
  
注解
+
笔记
  
These expressions are defined in <code>django.db.models.expressions</code> and
+
这些表达式在 <code>django.db.models.expressions</code> <code>django.db.models.aggregates</code> 中定义,但为了方便起见,它们可用并且通常从 [[../../../topics/db/models#module-django.db|django.db.models]] 导入。
<code>django.db.models.aggregates</code>, but for convenience they're available and
 
usually imported from [[../../../topics/db/models#module-django.db|<code>django.db.models</code>]].
 
  
  
第101行: 第94行:
 
<div id="f-expressions" class="section">
 
<div id="f-expressions" class="section">
  
=== <code>F()</code> expressions ===
+
=== F() 表达式 ===
  
; ''class'' <code>F</code>[[../../_modules/django/db/models/expressions.html#F|<span class="viewcode-link">[源代码]</span>]]
+
; ''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">F</span></span>
 
:  
 
:  
  
An <code>F()</code> object represents the value of a model field or annotated column. It
+
<code>F()</code> 对象表示模型字段或注释列的值。 它可以引用模型字段值并使用它们执行数据库操作,而实际上不必将它们从数据库中提取到 Python 内存中。
makes it possible to refer to model field values and perform database
 
operations using them without actually having to pull them out of the database
 
into Python memory.
 
  
Instead, Django uses the <code>F()</code> object to generate an SQL expression that
+
相反,Django 使用 <code>F()</code> 对象生成一个 SQL 表达式,该表达式描述了数据库级别所需的操作。
describes the required operation at the database level.
 
  
This is easiest to understand through an example. Normally, one might do
+
这通过一个例子最容易理解。 通常,人们可能会这样做:
something like this:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第121行: 第109行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre># Tintin filed a news story!
+
<syntaxhighlight lang="python"># Tintin filed a news story!
 
reporter = Reporters.objects.get(name='Tintin')
 
reporter = Reporters.objects.get(name='Tintin')
 
reporter.stories_filed += 1
 
reporter.stories_filed += 1
reporter.save()</pre>
+
reporter.save()</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Here, we have pulled the value of <code>reporter.stories_filed</code> from the database
+
在这里,我们已经将 <code>reporter.stories_filed</code> 的值从数据库拉入内存并使用熟悉的 Python 运算符对其进行操作,然后将对象保存回数据库。 但我们也可以这样做:
into memory and manipulated it using familiar Python operators, and then saved
 
the object back to the database. But instead we could also have done:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第137行: 第123行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>from django.db.models import F
+
<syntaxhighlight lang="python">from django.db.models import F
  
 
reporter = Reporters.objects.get(name='Tintin')
 
reporter = Reporters.objects.get(name='Tintin')
 
reporter.stories_filed = F('stories_filed') + 1
 
reporter.stories_filed = F('stories_filed') + 1
reporter.save()</pre>
+
reporter.save()</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Although <code>reporter.stories_filed = F('stories_filed') + 1</code> looks like a
+
尽管 <code>reporter.stories_filed = F('stories_filed') + 1</code> 看起来像一个普通的 Python 将值分配给实例属性,但实际上它是一个描述数据库操作的 SQL 构造。
normal Python assignment of value to an instance attribute, in fact it's an SQL
 
construct describing an operation on the database.
 
  
When Django encounters an instance of <code>F()</code>, it overrides the standard Python
+
Django 遇到 <code>F()</code> 的实例时,它会覆盖标准的 Python 操作符来创建一个封装的 SQL 表达式; 在这种情况下,它指示数据库增加由 <code>reporter.stories_filed</code> 表示的数据库字段。
operators to create an encapsulated SQL expression; in this case, one which
 
instructs the database to increment the database field represented by
 
<code>reporter.stories_filed</code>.
 
  
Whatever value is or was on <code>reporter.stories_filed</code>, Python never gets to
+
无论 <code>reporter.stories_filed</code> 上的值是什么或曾经是什么,Python 永远不会知道它——它完全由数据库处理。 通过 Django <code>F()</code> 类,Python 所做的一切就是创建 SQL 语法来引用该字段并描述操作。
know about it - it is dealt with entirely by the database. All Python does,
 
through Django's <code>F()</code> class, is create the SQL syntax to refer to the field
 
and describe the operation.
 
  
To access the new value saved this way, the object must be reloaded:
+
要访问以这种方式保存的新值,必须重新加载对象:
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第166行: 第144行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>reporter = Reporters.objects.get(pk=reporter.pk)
+
<syntaxhighlight lang="python">reporter = Reporters.objects.get(pk=reporter.pk)
 
# Or, more succinctly:
 
# Or, more succinctly:
reporter.refresh_from_db()</pre>
+
reporter.refresh_from_db()</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
As well as being used in operations on single instances as above, <code>F()</code> can
+
除了用于上述单个实例的操作外,<code>F()</code> 还可以用于对象实例的 <code>QuerySets</code>,与 <code>update()</code>。 这将我们上面使用的两个查询 - <code>get()</code> [[../instances#django.db.models.Model|save()]] - 减少到一个:
be used on <code>QuerySets</code> of object instances, with <code>update()</code>. This reduces
 
the two queries we were using above - the <code>get()</code> and the
 
[[../instances#django.db.models.Model|<code>save()</code>]] - to just one:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第182行: 第157行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>reporter = Reporters.objects.filter(name='Tintin')
+
<syntaxhighlight lang="python">reporter = Reporters.objects.filter(name='Tintin')
reporter.update(stories_filed=F('stories_filed') + 1)</pre>
+
reporter.update(stories_filed=F('stories_filed') + 1)</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
We can also use [[../querysets#django.db.models.query.QuerySet|<code>update()</code>]] to increment
+
我们还可以使用 [[../querysets#django.db.models.query.QuerySet|update()]] 来增加多个对象的字段值——这比从数据库中将它们全部拉入 Python、循环它们、增加每个对象的字段值要快得多,并将每个保存回数据库:
the field value on multiple objects - which could be very much faster than
 
pulling them all into Python from the database, looping over them, incrementing
 
the field value of each one, and saving each one back to the database:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第197行: 第169行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>Reporter.objects.all().update(stories_filed=F('stories_filed') + 1)</pre>
+
<syntaxhighlight lang="python">Reporter.objects.all().update(stories_filed=F('stories_filed') + 1)</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
<code>F()</code> therefore can offer performance advantages by:
+
<code>F()</code> 因此可以通过以下方式提供性能优势:
  
* getting the database, rather than Python, to do work
+
* 让数据库,而不是 Python 来完成工作
* reducing the number of queries some operations require
+
* 减少某些操作所需的查询次数
  
 
<div id="avoiding-race-conditions-using-f" class="section">
 
<div id="avoiding-race-conditions-using-f" class="section">
  
 
<span id="id1"></span>
 
<span id="id1"></span>
==== Avoiding race conditions using <code>F()</code> ====
+
==== 使用 F() 避免竞争条件 ====
  
Another useful benefit of <code>F()</code> is that having the database - rather than
+
<code>F()</code> 的另一个有用的好处是让数据库 - 而不是 Python - 更新字段的值避免了 ''竞争条件''
Python - update a field's value avoids a ''race condition''.
 
  
If two Python threads execute the code in the first example above, one thread
+
如果两个 Python 线程执行上面第一个示例中的代码,则一个线程可以在另一个线程从数据库中检索字段值后检索、递增和保存该字段的值。 第二个线程保存的值会以原来的值为准; 第一个线程的工作将简单地丢失。
could retrieve, increment, and save a field's value after the other has
 
retrieved it from the database. The value that the second thread saves will be
 
based on the original value; the work of the first thread will simply be lost.
 
  
If the database is responsible for updating the field, the process is more
+
如果数据库负责更新字段,则该过程更加健壮:它只会在 [[../instances#django.db.models.Model|save()]] <code>update()</code> 时根据数据库中字段的值更新字段] 被执行,而不是基于它在检索实例时的值。
robust: it will only ever update the field based on the value of the field in
 
the database when the [[../instances#django.db.models.Model|<code>save()</code>]] or <code>update()</code> is executed, rather
 
than based on its value when the instance was retrieved.
 
  
  
第229行: 第194行:
 
<div id="f-assignments-persist-after-model-save" class="section">
 
<div id="f-assignments-persist-after-model-save" class="section">
  
==== <code>F()</code> assignments persist after <code>Model.save()</code> ====
+
==== F() 分配在 Model.save() 之后仍然存在 ====
  
<code>F()</code> objects assigned to model fields persist after saving the model
+
<code>F()</code> 分配给模型字段的对象在保存模型实例后仍然存在,并将应用于每个 [[../instances#django.db.models.Model|save()]]。 例如:
instance and will be applied on each [[../instances#django.db.models.Model|<code>save()</code>]]. For example:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第238行: 第202行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>reporter = Reporters.objects.get(name='Tintin')
+
<syntaxhighlight lang="python">reporter = Reporters.objects.get(name='Tintin')
 
reporter.stories_filed = F('stories_filed') + 1
 
reporter.stories_filed = F('stories_filed') + 1
 
reporter.save()
 
reporter.save()
  
 
reporter.name = 'Tintin Jr.'
 
reporter.name = 'Tintin Jr.'
reporter.save()</pre>
+
reporter.save()</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
<code>stories_filed</code> will be updated twice in this case. If it's initially <code>1</code>,
+
在这种情况下,<code>stories_filed</code> 将更新两次。 如果最初为 <code>1</code>,则最终值为 <code>3</code>。 可以通过在保存模型对象后重新加载它来避免这种持久性,例如,通过使用 [[../instances#django.db.models.Model|refresh_from_db()]]
the final value will be <code>3</code>. This persistence can be avoided by reloading the
 
model object after saving it, for example, by using
 
[[../instances#django.db.models.Model|<code>refresh_from_db()</code>]].
 
  
  
第257行: 第218行:
 
<div id="using-f-in-filters" class="section">
 
<div id="using-f-in-filters" class="section">
  
==== Using <code>F()</code> in filters ====
+
==== 在过滤器中使用 F() ====
  
<code>F()</code> is also very useful in <code>QuerySet</code> filters, where they make it
+
<code>F()</code> <code>QuerySet</code> 过滤器中也非常有用,它们可以根据字段值而不是 Python 值根据条件过滤一组对象。
possible to filter a set of objects against criteria based on their field
 
values, rather than on Python values.
 
  
This is documented in [[../../../topics/db/queries#using-f-expressions-in-filters|<span class="std std-ref">using F() expressions in queries</span>]].
+
这在 [[../../../topics/db/queries#using-f-expressions-in-filters|中使用查询]] 中的 F() 表达式进行了记录。
  
  
第270行: 第229行:
  
 
<span id="id2"></span>
 
<span id="id2"></span>
==== Using <code>F()</code> with annotations ====
+
==== F() 与注释一起使用 ====
  
<code>F()</code> can be used to create dynamic fields on your models by combining
+
<code>F()</code> 可用于通过将不同字段与算术组合来在模型上创建动态字段:
different fields with arithmetic:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第279行: 第237行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>company = Company.objects.annotate(
+
<syntaxhighlight lang="python">company = Company.objects.annotate(
     chairs_needed=F('num_employees') - F('num_chairs'))</pre>
+
     chairs_needed=F('num_employees') - F('num_chairs'))</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
If the fields that you're combining are of different types you'll need
+
如果您组合的字段是不同类型的,您需要告诉 Django 将返回什么类型的字段。 由于 <code>F()</code> 不直接支持 <code>output_field</code>,您需要用 [[#django.db.models.ExpressionWrapper|ExpressionWrapper]] 包装表达式:
to tell Django what kind of field will be returned. Since <code>F()</code> does not
 
directly support <code>output_field</code> you will need to wrap the expression with
 
[[#django.db.models.ExpressionWrapper|<code>ExpressionWrapper</code>]]:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第294行: 第249行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>from django.db.models import DateTimeField, ExpressionWrapper, F
+
<syntaxhighlight lang="python">from django.db.models import DateTimeField, ExpressionWrapper, F
  
 
Ticket.objects.annotate(
 
Ticket.objects.annotate(
 
     expires=ExpressionWrapper(
 
     expires=ExpressionWrapper(
         F('active_at') + F('duration'), output_field=DateTimeField()))</pre>
+
         F('active_at') + F('duration'), output_field=DateTimeField()))</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
When referencing relational fields such as <code>ForeignKey</code>, <code>F()</code> returns the
+
引用 <code>ForeignKey</code> 等关系字段时,<code>F()</code> 返回主键值而不是模型实例:
primary key value rather than a model instance:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第310行: 第264行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt; car = Company.objects.annotate(built_by=F('manufacturer'))[0]
+
<syntaxhighlight lang="python">>> car = Company.objects.annotate(built_by=F('manufacturer'))[0]
&gt;&gt; car.manufacturer
+
>> car.manufacturer
&lt;Manufacturer: Toyota&gt;
+
<Manufacturer: Toyota>
&gt;&gt; car.built_by
+
>> car.built_by
3</pre>
+
3</syntaxhighlight>
  
 
</div>
 
</div>
第324行: 第278行:
  
 
<span id="id3"></span>
 
<span id="id3"></span>
==== Using <code>F()</code> to sort null values ====
+
==== 使用 F() 对空值进行排序 ====
  
Use <code>F()</code> and the <code>nulls_first</code> or <code>nulls_last</code> keyword argument to
+
使用 <code>F()</code> <code>nulls_first</code> <code>nulls_last</code> 关键字参数到 [[#django.db.models.Expression.asc|Expression.asc()]] [[#django.db.models.Expression.desc|desc()]] 来控制排序字段的空值。 默认情况下,排序取决于您的数据库。
[[#django.db.models.Expression.asc|<code>Expression.asc()</code>]] or [[#django.db.models.Expression.desc|<code>desc()</code>]] to control the ordering of
 
a field's null values. By default, the ordering depends on your database.
 
  
For example, to sort companies that haven't been contacted (<code>last_contacted</code>
+
例如,要在联系过的公司之后对未联系过的公司进行排序(<code>last_contacted</code> 为空):
is null) after companies that have been contacted:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第337行: 第288行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>from django.db.models import F
+
<syntaxhighlight lang="python">from django.db.models import F
Company.object.order_by(F('last_contacted').desc(nulls_last=True))</pre>
+
Company.object.order_by(F('last_contacted').desc(nulls_last=True))</syntaxhighlight>
  
 
</div>
 
</div>
第350行: 第301行:
  
 
<span id="id4"></span>
 
<span id="id4"></span>
=== <code>Func()</code> expressions ===
+
=== Func() 表达式 ===
  
<code>Func()</code> expressions are the base type of all expressions that involve
+
<code>Func()</code> 表达式是所有涉及数据库函数(如 <code>COALESCE</code> <code>LOWER</code>)或聚合(如 <code>SUM</code>)的基本类型。 它们可以直接使用:
database functions like <code>COALESCE</code> and <code>LOWER</code>, or aggregates like <code>SUM</code>.
 
They can be used directly:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第360行: 第309行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>from django.db.models import F, Func
+
<syntaxhighlight lang="python">from django.db.models import F, Func
  
queryset.annotate(field_lower=Func(F('field'), function='LOWER'))</pre>
+
queryset.annotate(field_lower=Func(F('field'), function='LOWER'))</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
or they can be used to build a library of database functions:
+
或者它们可用于构建数据库函数库:
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第373行: 第322行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>class Lower(Func):
+
<syntaxhighlight lang="python">class Lower(Func):
 
     function = 'LOWER'
 
     function = 'LOWER'
  
queryset.annotate(field_lower=Lower('field'))</pre>
+
queryset.annotate(field_lower=Lower('field'))</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
But both cases will result in a queryset where each model is annotated with an
+
但是这两种情况都会产生一个查询集,其中每个模型都用一个额外的属性 <code>field_lower</code> 进行注释,大致来自以下 SQL:
extra attribute <code>field_lower</code> produced, roughly, from the following SQL:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第388行: 第336行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>SELECT
+
<syntaxhighlight lang="python">SELECT
 
     ...
 
     ...
     LOWER(&quot;db_table&quot;.&quot;field&quot;) as &quot;field_lower&quot;</pre>
+
     LOWER("db_table"."field") as "field_lower"</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
See [[../database-functions|<span class="doc">Database Functions</span>]] for a list of built-in database functions.
+
有关内置数据库函数的列表,请参阅 [[../database-functions|数据库函数]]
  
The <code>Func</code> API is as follows:
+
<code>Func</code> API 如下:
  
 
<dl>
 
<dl>
<dt>''class'' <code>Func</code><span class="sig-paren">(</span>''<span class="o">*</span><span class="n">expressions</span>'', ''<span class="o">**</span><span class="n">extra</span>''<span class="sig-paren">)</span>[[../../_modules/django/db/models/expressions.html#Func|<span class="viewcode-link">[源代码]</span>]]</dt>
+
<dt>''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">Func</span></span><span class="sig-paren">(</span>''<span class="o"><span class="pre">*</span></span><span class="n"><span class="pre">expressions</span></span>'', ''<span class="o"><span class="pre">**</span></span><span class="n"><span class="pre">extra</span></span>''<span class="sig-paren">)</span></dt>
 
<dd><dl>
 
<dd><dl>
<dt><code>function</code></dt>
+
<dt><span class="sig-name descname"><span class="pre">function</span></span></dt>
<dd><p>A class attribute describing the function that will be generated.
+
<dd><p>描述将生成的函数的类属性。 具体来说,<code>function</code> 将作为 [[#django.db.models.Func.template|模板]] 内的 <code>function</code> 占位符进行插值。 默认为 <code>None</code></p></dd></dl>
Specifically, the <code>function</code> will be interpolated as the <code>function</code>
 
placeholder within [[#django.db.models.Func.template|<code>template</code>]]. Defaults to <code>None</code>.</p></dd></dl>
 
  
 
<dl>
 
<dl>
<dt><code>template</code></dt>
+
<dt><span class="sig-name descname"><span class="pre">template</span></span></dt>
<dd><p>A class attribute, as a format string, that describes the SQL that is
+
<dd><p>作为格式字符串的类属性,用于描述为此函数生成的 SQL。 默认为 <code>'%(function)s(%(expressions)s)'</code></p>
generated for this function. Defaults to
+
<p>如果您正在构建类似 <code>strftime('%W', 'date')</code> 的 SQL 并且需要在查询中使用文字 <code>%</code> 字符,请将其 (<code>%%%%</code>) <code>template</code> 属性中乘以四倍,因为字符串插值两次:一次是在 <code>as_sql()</code> 中的模板插值期间,一次是在使用数据库游标中的查询参数的 SQL 插值中。</p></dd></dl>
<code>'%(function)s(%(expressions)s)'</code>.</p>
 
<p>If you're constructing SQL like <code>strftime('%W', 'date')</code> and need a
 
literal <code>%</code> character in the query, quadruple it (<code>%%%%</code>) in the
 
<code>template</code> attribute because the string is interpolated twice: once
 
during the template interpolation in <code>as_sql()</code> and once in the SQL
 
interpolation with the query parameters in the database cursor.</p></dd></dl>
 
  
 
<dl>
 
<dl>
<dt><code>arg_joiner</code></dt>
+
<dt><span class="sig-name descname"><span class="pre">arg_joiner</span></span></dt>
<dd><p>A class attribute that denotes the character used to join the list of
+
<dd><p>一个类属性,表示用于将 <code>expressions</code> 列表连接在一起的字符。 默认为 <code>', '</code></p></dd></dl>
<code>expressions</code> together. Defaults to <code>', '</code>.</p></dd></dl>
 
  
 
<dl>
 
<dl>
<dt><code>arity</code></dt>
+
<dt><span class="sig-name descname"><span class="pre">arity</span></span></dt>
<dd><p>A class attribute that denotes the number of arguments the function
+
<dd><p>一个类属性,表示函数接受的参数数量。 如果设置了此属性并且使用不同数量的表达式调用函数,则会引发 <code>TypeError</code>。 默认为 <code>None</code></p></dd></dl>
accepts. If this attribute is set and the function is called with a
 
different number of expressions, <code>TypeError</code> will be raised. Defaults
 
to <code>None</code>.</p></dd></dl>
 
  
 
<dl>
 
<dl>
<dt><code>as_sql</code><span class="sig-paren">(</span>''<span class="n">compiler</span>'', ''<span class="n">connection</span>'', ''<span class="n">function</span><span class="o">=</span><span class="default_value">None</span>'', ''<span class="n">template</span><span class="o">=</span><span class="default_value">None</span>'', ''<span class="n">arg_joiner</span><span class="o">=</span><span class="default_value">None</span>'', ''<span class="o">**</span><span class="n">extra_context</span>''<span class="sig-paren">)</span>[[../../_modules/django/db/models/expressions.html#Func.as_sql|<span class="viewcode-link">[源代码]</span>]]</dt>
+
<dt><span class="sig-name descname"><span class="pre">as_sql</span></span><span class="sig-paren">(</span>''<span class="n"><span class="pre">compiler</span></span>'', ''<span class="n"><span class="pre">connection</span></span>'', ''<span class="n"><span class="pre">function</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span>'', ''<span class="n"><span class="pre">template</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span>'', ''<span class="n"><span class="pre">arg_joiner</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span>'', ''<span class="o"><span class="pre">**</span></span><span class="n"><span class="pre">extra_context</span></span>''<span class="sig-paren">)</span></dt>
<dd><p>Generates the SQL for the database function.</p>
+
<dd><p>为数据库函数生成 SQL。</p>
<p>The <code>as_vendor()</code> methods should use the <code>function</code>, <code>template</code>,
+
<p><code>as_vendor()</code> 方法应使用 <code>function</code><code>template</code><code>arg_joiner</code> 和任何其他 <code>**extra_context</code> 参数来根据需要自定义 SQL。 例如:</p>
<code>arg_joiner</code>, and any other <code>**extra_context</code> parameters to
 
customize the SQL as needed. For example:</p>
 
 
<div id="id5" class="literal-block-wrapper docutils container">
 
<div id="id5" class="literal-block-wrapper docutils container">
  
第447行: 第381行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>class ConcatPair(Func):
+
<syntaxhighlight lang="python">class ConcatPair(Func):
 
     ...
 
     ...
 
     function = 'CONCAT'
 
     function = 'CONCAT'
第456行: 第390行:
 
             compiler, connection,
 
             compiler, connection,
 
             function='CONCAT_WS',
 
             function='CONCAT_WS',
             template=&quot;%(function)s('', %(expressions)s)&quot;,
+
             template="%(function)s('', %(expressions)s)",
 
             **extra_context
 
             **extra_context
         )</pre>
+
         )</syntaxhighlight>
  
 
</div>
 
</div>
第465行: 第399行:
  
 
</div>
 
</div>
<p>To avoid a SQL injection vulnerability, <code>extra_context</code> [[#avoiding-sql-injection-in-query-expressions|<span class="std std-ref">must
+
<p>为了避免 SQL 注入漏洞,<code>extra_context</code> [[#avoiding-sql-injection-in-query-expressions|不得包含不受信任的用户输入]] ,因为这些值被插入到 SQL 字符串中,而不是作为查询参数传递,数据库驱动程序会在其中对它们进行转义。</p></dd></dl>
not contain untrusted user input</span>]]
 
as these values are interpolated into the SQL string rather than passed
 
as query parameters, where the database driver would escape them.</p></dd></dl>
 
 
</dd></dl>
 
</dd></dl>
  
The <code>*expressions</code> argument is a list of positional expressions that the
+
<code>*expressions</code> 参数是该函数将应用于的位置表达式列表。 表达式将转换为字符串,与 <code>arg_joiner</code> 连接在一起,然后作为 <code>expressions</code> 占位符插入到 <code>template</code> 中。
function will be applied to. The expressions will be converted to strings,
 
joined together with <code>arg_joiner</code>, and then interpolated into the <code>template</code>
 
as the <code>expressions</code> placeholder.
 
  
Positional arguments can be expressions or Python values. Strings are
+
位置参数可以是表达式或 Python 值。 字符串被假定为列引用并将被包装在 <code>F()</code> 表达式中,而其他值将被包装在 <code>Value()</code> 表达式中。
assumed to be column references and will be wrapped in <code>F()</code> expressions
 
while other values will be wrapped in <code>Value()</code> expressions.
 
  
The <code>**extra</code> kwargs are <code>key=value</code> pairs that can be interpolated
+
<code>**extra</code> kwargs <code>key=value</code> 对,可以插入到 <code>template</code> 属性中。 为避免 SQL 注入漏洞,<code>extra</code> [[#avoiding-sql-injection-in-query-expressions|不得包含不受信任的用户输入]] ,因为这些值被插入到 SQL 字符串中,而不是作为查询参数传递,数据库驱动程序会在其中对它们进行转义。
into the <code>template</code> attribute. To avoid a SQL injection vulnerability,
 
<code>extra</code> [[#avoiding-sql-injection-in-query-expressions|<span class="std std-ref">must not contain untrusted user input</span>]] as these values are interpolated
 
into the SQL string rather than passed as query parameters, where the database
 
driver would escape them.
 
  
The <code>function</code>, <code>template</code>, and <code>arg_joiner</code> keywords can be used to
+
<code>function</code><code>template</code> <code>arg_joiner</code> 关键字可用于替换同名的属性,而无需定义您自己的类。 <code>output_field</code> 可用于定义预期的返回类型。
replace the attributes of the same name without having to define your own
 
class. <code>output_field</code> can be used to define the expected return type.
 
  
  
第494行: 第414行:
 
<div id="aggregate-expressions" class="section">
 
<div id="aggregate-expressions" class="section">
  
=== <code>Aggregate()</code> expressions ===
+
=== Aggregate() 表达式 ===
  
An aggregate expression is a special case of a [[#func-expressions|<span class="std std-ref">Func() expression</span>]] that informs the query that a <code>GROUP BY</code> clause
+
聚合表达式是 [[#func-expressions|Func() 表达式]] 的一个特例,它通知查询需要一个 <code>GROUP BY</code> 子句。 所有 [[../querysets#aggregation-functions|聚合函数]] ,如 <code>Sum()</code> <code>Count()</code>,都继承自 <code>Aggregate()</code>
is required. All of the [[../querysets#aggregation-functions|<span class="std std-ref">aggregate functions</span>]],
 
like <code>Sum()</code> and <code>Count()</code>, inherit from <code>Aggregate()</code>.
 
  
Since <code>Aggregate</code>s are expressions and wrap expressions, you can represent
+
由于 <code>Aggregate</code>s 是表达式和包装表达式,您可以表示一些复杂的计算:
some complex computations:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第507行: 第424行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>from django.db.models import Count
+
<syntaxhighlight lang="python">from django.db.models import Count
  
 
Company.objects.annotate(
 
Company.objects.annotate(
     managers_required=(Count('num_employees') / 4) + Count('num_managers'))</pre>
+
     managers_required=(Count('num_employees') / 4) + Count('num_managers'))</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
The <code>Aggregate</code> API is as follows:
+
<code>Aggregate</code> API 如下:
  
 
<dl>
 
<dl>
<dt>''class'' <code>Aggregate</code><span class="sig-paren">(</span>''<span class="o">*</span><span class="n">expressions</span>'', ''<span class="n">output_field</span><span class="o">=</span><span class="default_value">None</span>'', ''<span class="n">distinct</span><span class="o">=</span><span class="default_value">False</span>'', ''<span class="n">filter</span><span class="o">=</span><span class="default_value">None</span>'', ''<span class="o">**</span><span class="n">extra</span>''<span class="sig-paren">)</span>[[../../_modules/django/db/models/aggregates.html#Aggregate|<span class="viewcode-link">[源代码]</span>]]</dt>
+
<dt>''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">Aggregate</span></span><span class="sig-paren">(</span>''<span class="o"><span class="pre">*</span></span><span class="n"><span class="pre">expressions</span></span>'', ''<span class="n"><span class="pre">output_field</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span>'', ''<span class="n"><span class="pre">distinct</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span>'', ''<span class="n"><span class="pre">filter</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span>'', ''<span class="o"><span class="pre">**</span></span><span class="n"><span class="pre">extra</span></span>''<span class="sig-paren">)</span></dt>
 
<dd><dl>
 
<dd><dl>
<dt><code>template</code></dt>
+
<dt><span class="sig-name descname"><span class="pre">template</span></span></dt>
<dd><p>A class attribute, as a format string, that describes the SQL that is
+
<dd><p>一个类属性,作为格式字符串,描述为此聚合生成的 SQL。 默认为 <code>'%(function)s(%(distinct)s%(expressions)s)'</code></p></dd></dl>
generated for this aggregate. Defaults to
 
<code>'%(function)s(%(distinct)s%(expressions)s)'</code>.</p></dd></dl>
 
  
 
<dl>
 
<dl>
<dt><code>function</code></dt>
+
<dt><span class="sig-name descname"><span class="pre">function</span></span></dt>
<dd><p>A class attribute describing the aggregate function that will be
+
<dd><p>描述将生成的聚合函数的类属性。 具体来说,<code>function</code> 将作为 [[#django.db.models.Aggregate.template|模板]] 内的 <code>function</code> 占位符进行插值。 默认为 <code>None</code></p></dd></dl>
generated. Specifically, the <code>function</code> will be interpolated as the
 
<code>function</code> placeholder within [[#django.db.models.Aggregate.template|<code>template</code>]]. Defaults to <code>None</code>.</p></dd></dl>
 
  
 
<dl>
 
<dl>
<dt><code>window_compatible</code></dt>
+
<dt><span class="sig-name descname"><span class="pre">window_compatible</span></span></dt>
<dd><p>Defaults to <code>True</code> since most aggregate functions can be used as the
+
<dd><p>默认为 <code>True</code>,因为大多数聚合函数都可以用作 [[#django.db.models.expressions.Window|Window]] 中的源表达式。</p></dd></dl>
source expression in [[#django.db.models.expressions.Window|<code>Window</code>]].</p></dd></dl>
 
  
 
<dl>
 
<dl>
<dt><code>allow_distinct</code></dt>
+
<dt><span class="sig-name descname"><span class="pre">allow_distinct</span></span></dt>
 
<dd><div class="versionadded">
 
<dd><div class="versionadded">
  
 
+
<p><span class="versionmodified added">2.2 版中的新功能。</span></p>
  
 
</div>
 
</div>
<p>A class attribute determining whether or not this aggregate function
+
<p>确定此聚合函数是否允许传递 <code>distinct</code> 关键字参数的类属性。 如果设置为 <code>False</code>(默认),如果通过 <code>distinct=True</code>,则会引发 <code>TypeError</code></p></dd></dl>
allows passing a <code>distinct</code> keyword argument. If set to <code>False</code>
 
(default), <code>TypeError</code> is raised if <code>distinct=True</code> is passed.</p></dd></dl>
 
 
</dd></dl>
 
</dd></dl>
  
The <code>expressions</code> positional arguments can include expressions or the names
+
<code>expressions</code> 位置参数可以包括表达式或模型字段的名称。 它们将被转换为字符串并用作 <code>template</code> 中的 <code>expressions</code> 占位符。
of model fields. They will be converted to a string and used as the
 
<code>expressions</code> placeholder within the <code>template</code>.
 
  
The <code>output_field</code> argument requires a model field instance, like
+
<code>output_field</code> 参数需要一个模型字段实例,如 <code>IntegerField()</code> <code>BooleanField()</code>,Django 将在从数据库中检索值后将其加载到其中。 通常在实例化模型字段时不需要参数,因为任何与数据验证相关的参数(<code>max_length</code><code>max_digits</code> 等)都不会在表达式的输出值上强制执行。
<code>IntegerField()</code> or <code>BooleanField()</code>, into which Django will load the value
 
after it's retrieved from the database. Usually no arguments are needed when
 
instantiating the model field as any arguments relating to data validation
 
(<code>max_length</code>, <code>max_digits</code>, etc.) will not be enforced on the expression's
 
output value.
 
  
Note that <code>output_field</code> is only required when Django is unable to determine
+
注意 <code>output_field</code> 仅在 Django 无法确定结果应该是什么字段类型时才需要。 混合字段类型的复杂表达式应定义所需的 <code>output_field</code>。 例如,将一个 <code>IntegerField()</code> 和一个 <code>FloatField()</code> 加在一起应该可能定义了 <code>output_field=FloatField()</code>
what field type the result should be. Complex expressions that mix field types
 
should define the desired <code>output_field</code>. For example, adding an
 
<code>IntegerField()</code> and a <code>FloatField()</code> together should probably have
 
<code>output_field=FloatField()</code> defined.
 
  
The <code>distinct</code> argument determines whether or not the aggregate function
+
<code>distinct</code> 参数确定是否应为 <code>expressions</code> 的每个不同值(或多个 <code>expressions</code> 的值集)调用聚合函数。 该参数仅在 [[#django.db.models.Aggregate.allow_distinct|allow_distinct]] 设置为 <code>True</code> 的聚合上受支持。
should be invoked for each distinct value of <code>expressions</code> (or set of
 
values, for multiple <code>expressions</code>). The argument is only supported on
 
aggregates that have [[#django.db.models.Aggregate.allow_distinct|<code>allow_distinct</code>]] set to <code>True</code>.
 
  
The <code>filter</code> argument takes a [[../querysets#django.db.models|<code>Q object</code>]] that's
+
<code>filter</code> 参数采用 [[../querysets#django.db.models|Q 对象]] ,用于过滤聚合的行。 有关示例用法,请参阅 [[../conditional-expressions#conditional-aggregation|条件聚合]] [[../../../topics/db/aggregation#filtering-on-annotations|注释过滤]]
used to filter the rows that are aggregated. See [[../conditional-expressions#conditional-aggregation|<span class="std std-ref">Conditional aggregation</span>]]
 
and [[../../../topics/db/aggregation#filtering-on-annotations|<span class="std std-ref">过滤注解</span>]] for example usage.
 
  
The <code>**extra</code> kwargs are <code>key=value</code> pairs that can be interpolated
+
<code>**extra</code> kwargs <code>key=value</code> 对,可以插入到 <code>template</code> 属性中。
into the <code>template</code> attribute.
 
  
 
<div class="versionadded">
 
<div class="versionadded">
  
The <code>allow_distinct</code> attribute and <code>distinct</code> argument were added.
+
<span class="versionmodified added"> 2.2 新功能: </span> 添加了 <code>allow_distinct</code> 属性和 <code>distinct</code> 参数。
  
  
第587行: 第480行:
 
<div id="creating-your-own-aggregate-functions" class="section">
 
<div id="creating-your-own-aggregate-functions" class="section">
  
=== Creating your own Aggregate Functions ===
+
=== 创建你自己的聚合函数 ===
  
Creating your own aggregate is extremely easy. At a minimum, you need
+
创建自己的聚合非常容易。 至少,您需要定义 <code>function</code>,但您也可以完全自定义生成的 SQL。 下面是一个简短的例子:
to define <code>function</code>, but you can also completely customize the
 
SQL that is generated. Here's a brief example:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第597行: 第488行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>from django.db.models import Aggregate
+
<syntaxhighlight lang="python">from django.db.models import Aggregate
  
 
class Sum(Aggregate):
 
class Sum(Aggregate):
第610行: 第501行:
 
             all_values='ALL ' if all_values else '',
 
             all_values='ALL ' if all_values else '',
 
             **extra
 
             **extra
         )</pre>
+
         )</syntaxhighlight>
  
 
</div>
 
</div>
第619行: 第510行:
 
<div id="value-expressions" class="section">
 
<div id="value-expressions" class="section">
  
=== <code>Value()</code> expressions ===
+
=== Value() 表达式 ===
  
; ''class'' <code>Value</code><span class="sig-paren">(</span>''<span class="n">value</span>'', ''<span class="n">output_field</span><span class="o">=</span><span class="default_value">None</span>''<span class="sig-paren">)</span>[[../../_modules/django/db/models/expressions.html#Value|<span class="viewcode-link">[源代码]</span>]]
+
; ''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">Value</span></span><span class="sig-paren">(</span>''<span class="n"><span class="pre">value</span></span>'', ''<span class="n"><span class="pre">output_field</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span>''<span class="sig-paren">)</span>
 
:  
 
:  
  
A <code>Value()</code> object represents the smallest possible component of an
+
<code>Value()</code> 对象表示表达式的最小可能组件:一个简单的值。 当您需要在表达式中表示整数、布尔值或字符串的值时,您可以将该值包装在 <code>Value()</code> 中。
expression: a simple value. When you need to represent the value of an integer,
 
boolean, or string within an expression, you can wrap that value within a
 
<code>Value()</code>.
 
  
You will rarely need to use <code>Value()</code> directly. When you write the expression
+
您很少需要直接使用 <code>Value()</code>。 当您编写表达式 <code>F('field') + 1</code> 时,Django 将 <code>1</code> 隐式包装在 <code>Value()</code> 中,从而允许在更复杂的表达式中使用简单的值。 当您想将字符串传递给表达式时,您需要使用 <code>Value()</code>。 大多数表达式将字符串参数解释为字段的名称,例如 <code>Lower('name')</code>
<code>F('field') + 1</code>, Django implicitly wraps the <code>1</code> in a <code>Value()</code>,
 
allowing simple values to be used in more complex expressions. You will need to
 
use <code>Value()</code> when you want to pass a string to an expression. Most
 
expressions interpret a string argument as the name of a field, like
 
<code>Lower('name')</code>.
 
  
The <code>value</code> argument describes the value to be included in the expression,
+
<code>value</code> 参数描述要包含在表达式中的值,例如 <code>1</code><code>True</code> <code>None</code>Django 知道如何将这些 Python 值转换为它们对应的数据库类型。
such as <code>1</code>, <code>True</code>, or <code>None</code>. Django knows how to convert these Python
 
values into their corresponding database type.
 
  
The <code>output_field</code> argument should be a model field instance, like
+
<code>output_field</code> 参数应该是一个模型字段实例,如 <code>IntegerField()</code> <code>BooleanField()</code>,Django 将在从数据库中检索值后将其加载到其中。 通常在实例化模型字段时不需要参数,因为任何与数据验证相关的参数(<code>max_length</code><code>max_digits</code> 等)都不会在表达式的输出值上强制执行。
<code>IntegerField()</code> or <code>BooleanField()</code>, into which Django will load the value
 
after it's retrieved from the database. Usually no arguments are needed when
 
instantiating the model field as any arguments relating to data validation
 
(<code>max_length</code>, <code>max_digits</code>, etc.) will not be enforced on the expression's
 
output value.
 
  
  
第651行: 第527行:
 
<div id="expressionwrapper-expressions" class="section">
 
<div id="expressionwrapper-expressions" class="section">
  
=== <code>ExpressionWrapper()</code> expressions ===
+
=== ExpressionWrapper() 表达式 ===
  
; ''class'' <code>ExpressionWrapper</code><span class="sig-paren">(</span>''<span class="n">expression</span>'', ''<span class="n">output_field</span>''<span class="sig-paren">)</span>[[../../_modules/django/db/models/expressions.html#ExpressionWrapper|<span class="viewcode-link">[源代码]</span>]]
+
; ''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">ExpressionWrapper</span></span><span class="sig-paren">(</span>''<span class="n"><span class="pre">expression</span></span>'', ''<span class="n"><span class="pre">output_field</span></span>''<span class="sig-paren">)</span>
 
:  
 
:  
  
<code>ExpressionWrapper</code> simply surrounds another expression and provides access
+
<code>ExpressionWrapper</code> 只是围绕另一个表达式,并提供对其他表达式可能不可用的属性的访问,例如 <code>output_field</code><code>ExpressionWrapper</code> 在对具有不同类型的 <code>F()</code> 表达式使用算术时是必需的,如 [[#using-f-with-annotations|使用带注释的 F()]] 中所述。
to properties, such as <code>output_field</code>, that may not be available on other
 
expressions. <code>ExpressionWrapper</code> is necessary when using arithmetic on
 
<code>F()</code> expressions with different types as described in
 
[[#using-f-with-annotations|<span class="std std-ref">Using F() with annotations</span>]].
 
  
  
第666行: 第538行:
 
<div id="conditional-expressions" class="section">
 
<div id="conditional-expressions" class="section">
  
=== Conditional expressions ===
+
=== 条件表达式 ===
  
Conditional expressions allow you to use <code>if</code> ... <code>elif</code> ...
+
条件表达式允许您在查询中使用 <code>if</code> ... <code>elif</code> ... <code>else</code> 逻辑。 Django 本身支持 SQL <code>CASE</code> 表达式。 有关更多详细信息,请参阅 [[../conditional-expressions|条件表达式]]
<code>else</code> logic in queries. Django natively supports SQL <code>CASE</code>
 
expressions. For more details see [[../conditional-expressions|<span class="doc">Conditional Expressions</span>]].
 
  
  
第676行: 第546行:
 
<div id="subquery-expressions" class="section">
 
<div id="subquery-expressions" class="section">
  
=== <code>Subquery()</code> expressions ===
+
=== Subquery() 表达式 ===
  
; ''class'' <code>Subquery</code><span class="sig-paren">(</span>''<span class="n">queryset</span>'', ''<span class="n">output_field</span><span class="o">=</span><span class="default_value">None</span>''<span class="sig-paren">)</span>[[../../_modules/django/db/models/expressions.html#Subquery|<span class="viewcode-link">[源代码]</span>]]
+
; ''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">Subquery</span></span><span class="sig-paren">(</span>''<span class="n"><span class="pre">queryset</span></span>'', ''<span class="n"><span class="pre">output_field</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span>''<span class="sig-paren">)</span>
 
:  
 
:  
  
You can add an explicit subquery to a <code>QuerySet</code> using the <code>Subquery</code>
+
您可以使用 <code>Subquery</code> 表达式向 <code>QuerySet</code> 添加显式子查询。
expression.
 
  
For example, to annotate each post with the email address of the author of the
+
例如,要使用该帖子的最新评论的作者的电子邮件地址来注释每个帖子:
newest comment on that post:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第691行: 第559行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; from django.db.models import OuterRef, Subquery
+
<syntaxhighlight lang="python">>>> from django.db.models import OuterRef, Subquery
&gt;&gt;&gt; newest = Comment.objects.filter(post=OuterRef('pk')).order_by('-created_at')
+
>>> newest = Comment.objects.filter(post=OuterRef('pk')).order_by('-created_at')
&gt;&gt;&gt; Post.objects.annotate(newest_commenter_email=Subquery(newest.values('email')[:1]))</pre>
+
>>> Post.objects.annotate(newest_commenter_email=Subquery(newest.values('email')[:1]))</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
On PostgreSQL, the SQL looks like:
+
PostgreSQL 上,SQL 看起来像:
  
 
<div class="highlight-sql notranslate">
 
<div class="highlight-sql notranslate">
第704行: 第572行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>SELECT &quot;post&quot;.&quot;id&quot;, (
+
<syntaxhighlight lang="sql">SELECT "post"."id", (
     SELECT U0.&quot;email&quot;
+
     SELECT U0."email"
     FROM &quot;comment&quot; U0
+
     FROM "comment" U0
     WHERE U0.&quot;post_id&quot; = (&quot;post&quot;.&quot;id&quot;)
+
     WHERE U0."post_id" = ("post"."id")
     ORDER BY U0.&quot;created_at&quot; DESC LIMIT 1
+
     ORDER BY U0."created_at" DESC LIMIT 1
) AS &quot;newest_commenter_email&quot; FROM &quot;post&quot;</pre>
+
) AS "newest_commenter_email" FROM "post"</syntaxhighlight>
  
 
</div>
 
</div>
第716行: 第584行:
 
<div class="admonition note">
 
<div class="admonition note">
  
注解
+
笔记
  
The examples in this section are designed to show how to force
+
本节中的示例旨在展示如何强制 Django 执行子查询。 在某些情况下,可以编写一个等效的查询集来更清晰或更高效地执行相同的任务。
Django to execute a subquery. In some cases it may be possible to
 
write an equivalent queryset that performs the same task more
 
clearly or efficiently.
 
  
  
第727行: 第592行:
 
<div id="referencing-columns-from-the-outer-queryset" class="section">
 
<div id="referencing-columns-from-the-outer-queryset" class="section">
  
==== Referencing columns from the outer queryset ====
+
==== 从外部查询集中引用列 ====
  
; ''class'' <code>OuterRef</code><span class="sig-paren">(</span>''<span class="n">field</span>''<span class="sig-paren">)</span>[[../../_modules/django/db/models/expressions.html#OuterRef|<span class="viewcode-link">[源代码]</span>]]
+
; ''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">OuterRef</span></span><span class="sig-paren">(</span>''<span class="n"><span class="pre">field</span></span>''<span class="sig-paren">)</span>
 
:  
 
:  
  
Use <code>OuterRef</code> when a queryset in a <code>Subquery</code> needs to refer to a field
+
<code>Subquery</code> 中的查询集需要引用外部查询中的字段时,请使用 <code>OuterRef</code>。 它的作用类似于 [[#django.db.models.F|F]] 表达式,只是在解析外部查询集之前不会检查它是否引用了有效字段。
from the outer query. It acts like an [[#django.db.models.F|<code>F</code>]] expression except that the
 
check to see if it refers to a valid field isn't made until the outer queryset
 
is resolved.
 
  
Instances of <code>OuterRef</code> may be used in conjunction with nested instances
+
<code>OuterRef</code> 的实例可以与 <code>Subquery</code> 的嵌套实例结合使用,以引用不是直接父级的包含查询集。 例如,这个查询集需要在一对嵌套的 <code>Subquery</code> 实例中才能正确解析:
of <code>Subquery</code> to refer to a containing queryset that isn't the immediate
 
parent. For example, this queryset would need to be within a nested pair of
 
<code>Subquery</code> instances to resolve correctly:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第746行: 第605行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; Book.objects.filter(author=OuterRef(OuterRef('pk')))</pre>
+
<syntaxhighlight lang="python">>>> Book.objects.filter(author=OuterRef(OuterRef('pk')))</syntaxhighlight>
  
 
</div>
 
</div>
第755行: 第614行:
 
<div id="limiting-a-subquery-to-a-single-column" class="section">
 
<div id="limiting-a-subquery-to-a-single-column" class="section">
  
==== Limiting a subquery to a single column ====
+
==== 将子查询限制为单列 ====
  
There are times when a single column must be returned from a <code>Subquery</code>, for
+
有时必须从 <code>Subquery</code> 返回单个列,例如,使用 <code>Subquery</code> 作为 <code>__in</code> 查找的目标。 要返回最后一天内发布的帖子的所有评论:
instance, to use a <code>Subquery</code> as the target of an <code>__in</code> lookup. To return
 
all comments for posts published within the last day:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第765行: 第622行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; from datetime import timedelta
+
<syntaxhighlight lang="python">>>> from datetime import timedelta
&gt;&gt;&gt; from django.utils import timezone
+
>>> from django.utils import timezone
&gt;&gt;&gt; one_day_ago = timezone.now() - timedelta(days=1)
+
>>> one_day_ago = timezone.now() - timedelta(days=1)
&gt;&gt;&gt; posts = Post.objects.filter(published_at__gte=one_day_ago)
+
>>> posts = Post.objects.filter(published_at__gte=one_day_ago)
&gt;&gt;&gt; Comment.objects.filter(post__in=Subquery(posts.values('pk')))</pre>
+
>>> Comment.objects.filter(post__in=Subquery(posts.values('pk')))</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
In this case, the subquery must use [[../querysets#django.db.models.query.QuerySet|<code>values()</code>]]
+
在这种情况下,子查询必须使用 [[../querysets#django.db.models.query.QuerySet|values()]] 仅返回单个列:帖子的主键。
to return only a single column: the primary key of the post.
 
  
  
第781行: 第637行:
 
<div id="limiting-the-subquery-to-a-single-row" class="section">
 
<div id="limiting-the-subquery-to-a-single-row" class="section">
  
==== Limiting the subquery to a single row ====
+
==== 将子查询限制为单行 ====
  
To prevent a subquery from returning multiple rows, a slice (<code>[:1]</code>) of the
+
为了防止子查询返回多行,使用了查询集的切片 (<code>[:1]</code>)
queryset is used:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第790行: 第645行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; subquery = Subquery(newest.values('email')[:1])
+
<syntaxhighlight lang="python">>>> subquery = Subquery(newest.values('email')[:1])
&gt;&gt;&gt; Post.objects.annotate(newest_commenter_email=subquery)</pre>
+
>>> Post.objects.annotate(newest_commenter_email=subquery)</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
In this case, the subquery must only return a single column ''and'' a single
+
在这种情况下,子查询必须只返回单列 ''和单行'' :最近创建的评论的电子邮件地址。
row: the email address of the most recently created comment.
 
  
(Using [[../querysets#django.db.models.query.QuerySet|<code>get()</code>]] instead of a slice would fail because the
+
(使用 [[../querysets#django.db.models.query.QuerySet|get()]] 而不是切片会失败,因为在 <code>Subquery</code> 中使用查询集之前,无法解析 <code>OuterRef</code>。)
<code>OuterRef</code> cannot be resolved until the queryset is used within a
 
<code>Subquery</code>.)
 
  
  
第807行: 第659行:
 
<div id="exists-subqueries" class="section">
 
<div id="exists-subqueries" class="section">
  
==== <code>Exists()</code> subqueries ====
+
==== Exists() 子查询 ====
  
; ''class'' <code>Exists</code><span class="sig-paren">(</span>''<span class="n">queryset</span>''<span class="sig-paren">)</span>[[../../_modules/django/db/models/expressions.html#Exists|<span class="viewcode-link">[源代码]</span>]]
+
; ''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">Exists</span></span><span class="sig-paren">(</span>''<span class="n"><span class="pre">queryset</span></span>''<span class="sig-paren">)</span>
 
:  
 
:  
  
<code>Exists</code> is a <code>Subquery</code> subclass that uses an SQL <code>EXISTS</code> statement. In
+
<code>Exists</code> 是使用 SQL <code>EXISTS</code> 语句的 <code>Subquery</code> 子类。 在许多情况下,它会比子查询执行得更好,因为当找到第一个匹配行时,数据库能够停止对子查询的评估。
many cases it will perform better than a subquery since the database is able to
 
stop evaluation of the subquery when a first matching row is found.
 
  
For example, to annotate each post with whether or not it has a comment from
+
例如,要注释每个帖子是否有最后一天的评论:
within the last day:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第823行: 第672行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; from django.db.models import Exists, OuterRef
+
<syntaxhighlight lang="python">>>> from django.db.models import Exists, OuterRef
&gt;&gt;&gt; from datetime import timedelta
+
>>> from datetime import timedelta
&gt;&gt;&gt; from django.utils import timezone
+
>>> from django.utils import timezone
&gt;&gt;&gt; one_day_ago = timezone.now() - timedelta(days=1)
+
>>> one_day_ago = timezone.now() - timedelta(days=1)
&gt;&gt;&gt; recent_comments = Comment.objects.filter(
+
>>> recent_comments = Comment.objects.filter(
 
...    post=OuterRef('pk'),
 
...    post=OuterRef('pk'),
 
...    created_at__gte=one_day_ago,
 
...    created_at__gte=one_day_ago,
 
... )
 
... )
&gt;&gt;&gt; Post.objects.annotate(recent_comment=Exists(recent_comments))</pre>
+
>>> Post.objects.annotate(recent_comment=Exists(recent_comments))</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
On PostgreSQL, the SQL looks like:
+
PostgreSQL 上,SQL 看起来像:
  
 
<div class="highlight-sql notranslate">
 
<div class="highlight-sql notranslate">
第842行: 第691行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>SELECT &quot;post&quot;.&quot;id&quot;, &quot;post&quot;.&quot;published_at&quot;, EXISTS(
+
<syntaxhighlight lang="sql">SELECT "post"."id", "post"."published_at", EXISTS(
     SELECT U0.&quot;id&quot;, U0.&quot;post_id&quot;, U0.&quot;email&quot;, U0.&quot;created_at&quot;
+
     SELECT U0."id", U0."post_id", U0."email", U0."created_at"
     FROM &quot;comment&quot; U0
+
     FROM "comment" U0
 
     WHERE (
 
     WHERE (
         U0.&quot;created_at&quot; &gt;= YYYY-MM-DD HH:MM:SS AND
+
         U0."created_at" >= YYYY-MM-DD HH:MM:SS AND
         U0.&quot;post_id&quot; = (&quot;post&quot;.&quot;id&quot;)
+
         U0."post_id" = ("post"."id")
 
     )
 
     )
) AS &quot;recent_comment&quot; FROM &quot;post&quot;</pre>
+
) AS "recent_comment" FROM "post"</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
It's unnecessary to force <code>Exists</code> to refer to a single column, since the
+
没有必要强制 <code>Exists</code> 引用单个列,因为这些列被丢弃并返回一个布尔结果。 同样,由于排序在 SQL <code>EXISTS</code> 子查询中并不重要,只会降低性能,因此它会被自动删除。
columns are discarded and a boolean result is returned. Similarly, since
 
ordering is unimportant within an SQL <code>EXISTS</code> subquery and would only
 
degrade performance, it's automatically removed.
 
  
You can query using <code>NOT EXISTS</code> with <code>~Exists()</code>.
+
您可以使用 <code>NOT EXISTS</code> <code>~Exists()</code> 进行查询。
  
  
第865行: 第711行:
 
<div id="filtering-on-a-subquery-expression" class="section">
 
<div id="filtering-on-a-subquery-expression" class="section">
  
==== Filtering on a <code>Subquery</code> expression ====
+
==== 过滤 Subquery 表达式 ====
  
It's not possible to filter directly using <code>Subquery</code> and <code>Exists</code>, e.g.:
+
无法直接使用 <code>Subquery</code> <code>Exists</code> 进行过滤,例如:
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第873行: 第719行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; Post.objects.filter(Exists(recent_comments))
+
<syntaxhighlight lang="python">>>> Post.objects.filter(Exists(recent_comments))
 
...
 
...
TypeError: 'Exists' object is not iterable</pre>
+
TypeError: 'Exists' object is not iterable</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
You must filter on a subquery expression by first annotating the queryset
+
您必须首先注释查询集,然后根据该注释过滤子查询表达式:
and then filtering based on that annotation:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第887行: 第732行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; Post.objects.annotate(
+
<syntaxhighlight lang="python">>>> Post.objects.annotate(
 
...    recent_comment=Exists(recent_comments),
 
...    recent_comment=Exists(recent_comments),
... ).filter(recent_comment=True)</pre>
+
... ).filter(recent_comment=True)</syntaxhighlight>
  
 
</div>
 
</div>
第898行: 第743行:
 
<div id="using-aggregates-within-a-subquery-expression" class="section">
 
<div id="using-aggregates-within-a-subquery-expression" class="section">
  
==== Using aggregates within a <code>Subquery</code> expression ====
+
==== Subquery 表达式中使用聚合 ====
  
Aggregates may be used within a <code>Subquery</code>, but they require a specific
+
聚合可以在 <code>Subquery</code> 中使用,但它们需要 [[../querysets#django.db.models.query.QuerySet|filter()]][[../querysets#django.db.models.query.QuerySet|values()]] [[../querysets#django.db.models.query.QuerySet|annotate()]] 的特定组合以获得正确的子查询分组。
combination of [[../querysets#django.db.models.query.QuerySet|<code>filter()</code>]], [[../querysets#django.db.models.query.QuerySet|<code>values()</code>]], and
 
[[../querysets#django.db.models.query.QuerySet|<code>annotate()</code>]] to get the subquery grouping correct.
 
  
Assuming both models have a <code>length</code> field, to find posts where the post
+
假设两个模型都有一个 <code>length</code> 字段,以查找帖子长度大于所有组合评论总长度的帖子:
length is greater than the total length of all combined comments:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第911行: 第753行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; from django.db.models import OuterRef, Subquery, Sum
+
<syntaxhighlight lang="python">>>> from django.db.models import OuterRef, Subquery, Sum
&gt;&gt;&gt; comments = Comment.objects.filter(post=OuterRef('pk')).order_by().values('post')
+
>>> comments = Comment.objects.filter(post=OuterRef('pk')).order_by().values('post')
&gt;&gt;&gt; total_comments = comments.annotate(total=Sum('length')).values('total')
+
>>> total_comments = comments.annotate(total=Sum('length')).values('total')
&gt;&gt;&gt; Post.objects.filter(length__gt=Subquery(total_comments))</pre>
+
>>> Post.objects.filter(length__gt=Subquery(total_comments))</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
The initial <code>filter(...)</code> limits the subquery to the relevant parameters.
+
初始的 <code>filter(...)</code> 将子查询限制为相关参数。 <code>order_by()</code> 删除 <code>Comment</code> 模型上的默认 [[../options#django.db.models.Options|排序]] (如果有)。 <code>values('post')</code> 汇总了 <code>Post</code> 的评论。 最后,<code>annotate(...)</code> 执行聚合。 应用这些查询集方法的顺序很重要。 在这种情况下,由于子查询必须限制为单个列,因此需要 <code>values('total')</code>
<code>order_by()</code> removes the default [[../options#django.db.models.Options|<code>ordering</code>]]
 
(if any) on the <code>Comment</code> model. <code>values('post')</code> aggregates comments by
 
<code>Post</code>. Finally, <code>annotate(...)</code> performs the aggregation. The order in
 
which these queryset methods are applied is important. In this case, since the
 
subquery must be limited to a single column, <code>values('total')</code> is required.
 
  
This is the only way to perform an aggregation within a <code>Subquery</code>, as
+
这是在 <code>Subquery</code> 中执行聚合的唯一方法,因为使用 [[../querysets#django.db.models.query.QuerySet|aggregate()]] 尝试评估查询集(如果有 <code>OuterRef</code>,这不会可以解决)。
using [[../querysets#django.db.models.query.QuerySet|<code>aggregate()</code>]] attempts to evaluate the queryset (and if
 
there is an <code>OuterRef</code>, this will not be possible to resolve).
 
  
  
第936行: 第771行:
 
<div id="raw-sql-expressions" class="section">
 
<div id="raw-sql-expressions" class="section">
  
=== Raw SQL expressions ===
+
=== 原始 SQL 表达式 ===
  
; ''class'' <code>RawSQL</code><span class="sig-paren">(</span>''<span class="n">sql</span>'', ''<span class="n">params</span>'', ''<span class="n">output_field</span><span class="o">=</span><span class="default_value">None</span>''<span class="sig-paren">)</span>[[../../_modules/django/db/models/expressions.html#RawSQL|<span class="viewcode-link">[源代码]</span>]]
+
; ''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">RawSQL</span></span><span class="sig-paren">(</span>''<span class="n"><span class="pre">sql</span></span>'', ''<span class="n"><span class="pre">params</span></span>'', ''<span class="n"><span class="pre">output_field</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span>''<span class="sig-paren">)</span>
 
:  
 
:  
  
Sometimes database expressions can't easily express a complex <code>WHERE</code> clause.
+
有时数据库表达式不能轻易表达复杂的 <code>WHERE</code> 子句。 在这些边缘情况下,请使用 <code>RawSQL</code> 表达式。 例如:
In these edge cases, use the <code>RawSQL</code> expression. For example:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第948行: 第782行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; from django.db.models.expressions import RawSQL
+
<syntaxhighlight lang="python">>>> from django.db.models.expressions import RawSQL
&gt;&gt;&gt; queryset.annotate(val=RawSQL(&quot;select col from sometable where othercol = %s&quot;, (someparam,)))</pre>
+
>>> queryset.annotate(val=RawSQL("select col from sometable where othercol = %s", (someparam,)))</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
These extra lookups may not be portable to different database engines (because
+
这些额外的查找可能无法移植到不同的数据库引擎(因为您正在明确编写 SQL 代码)并且违反 DRY 原则,因此您应该尽可能避免它们。
you're explicitly writing SQL code) and violate the DRY principle, so you
 
should avoid them if possible.
 
  
 
<div class="admonition warning">
 
<div class="admonition warning">
第962行: 第794行:
 
警告
 
警告
  
To protect against [https://en.wikipedia.org/wiki/SQL_injection SQL injection attacks], you must escape any
+
为了防止 [https://en.wikipedia.org/wiki/SQL_injection SQL 注入攻击] ,您必须转义用户可以使用 <code>params</code> 控制的任何参数。 <code>params</code> 是强制您承认您没有使用用户提供的数据插入 SQL 的必需参数。
parameters that the user can control by using <code>params</code>. <code>params</code> is a
 
required argument to force you to acknowledge that you're not interpolating
 
your SQL with user-provided data.
 
  
You also must not quote placeholders in the SQL string. This example is
+
您也不得在 SQL 字符串中引用占位符。 由于 <code>%s</code> 周围的引号,此示例容易受到 SQL 注入攻击:
vulnerable to SQL injection because of the quotes around <code>%s</code>:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第974行: 第802行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>RawSQL(&quot;select col from sometable where othercol = '%s'&quot;)  # unsafe!</pre>
+
<syntaxhighlight lang="python">RawSQL("select col from sometable where othercol = '%s'")  # unsafe!</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
You can read more about how Django's [[../../../topics/security#sql-injection-protection|<span class="std std-ref">SQL injection protection</span>]] works.
+
您可以阅读有关 Django [[../../../topics/security#sql-injection-protection|SQL 注入保护]] 工作原理的更多信息。
  
  
第987行: 第815行:
 
<div id="window-functions" class="section">
 
<div id="window-functions" class="section">
  
=== Window functions ===
+
=== 窗口函数 ===
  
Window functions provide a way to apply functions on partitions. Unlike a
+
窗口函数提供了一种在分区上应用函数的方法。 与为 group by 定义的每个集合计算最终结果的普通聚合函数不同,窗口函数对 [[#window-frames|]] 和分区进行操作,并计算每一行的结果。
normal aggregation function which computes a final result for each set defined
 
by the group by, window functions operate on [[#window-frames|<span class="std std-ref">frames</span>]] and
 
partitions, and compute the result for each row.
 
  
You can specify multiple windows in the same query which in Django ORM would be
+
您可以在同一个查询中指定多个窗口,这在 Django ORM 中相当于在 [[../../../topics/db/aggregation|QuerySet.annotate()]] 调用中包含多个表达式。 ORM 不使用命名窗口,而是它们是选定列的一部分。
equivalent to including multiple expressions in a [[../../../topics/db/aggregation|<span class="doc">QuerySet.annotate()</span>]] call. The ORM doesn't make use of named windows,
 
instead they are part of the selected columns.
 
  
 
<dl>
 
<dl>
<dt>''class'' <code>Window</code><span class="sig-paren">(</span>''<span class="n">expression</span>'', ''<span class="n">partition_by</span><span class="o">=</span><span class="default_value">None</span>'', ''<span class="n">order_by</span><span class="o">=</span><span class="default_value">None</span>'', ''<span class="n">frame</span><span class="o">=</span><span class="default_value">None</span>'', ''<span class="n">output_field</span><span class="o">=</span><span class="default_value">None</span>''<span class="sig-paren">)</span>[[../../_modules/django/db/models/expressions.html#Window|<span class="viewcode-link">[源代码]</span>]]</dt>
+
<dt>''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">Window</span></span><span class="sig-paren">(</span>''<span class="n"><span class="pre">expression</span></span>'', ''<span class="n"><span class="pre">partition_by</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span>'', ''<span class="n"><span class="pre">order_by</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span>'', ''<span class="n"><span class="pre">frame</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span>'', ''<span class="n"><span class="pre">output_field</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span>''<span class="sig-paren">)</span></dt>
 
<dd><dl>
 
<dd><dl>
<dt><code>filterable</code></dt>
+
<dt><span class="sig-name descname"><span class="pre">filterable</span></span></dt>
<dd><p>Defaults to <code>False</code>. The SQL standard disallows referencing window
+
<dd><p>默认为 <code>False</code>SQL 标准不允许在 <code>WHERE</code> 子句中引用窗口函数,并且 Django 在构造一个 <code>QuerySet</code> 时会引发异常。</p></dd></dl>
functions in the <code>WHERE</code> clause and Django raises an exception when
 
constructing a <code>QuerySet</code> that would do that.</p></dd></dl>
 
  
 
<dl>
 
<dl>
<dt><code>template</code></dt>
+
<dt><span class="sig-name descname"><span class="pre">template</span></span></dt>
<dd><p>Defaults to <code>%(expression)s OVER (%(window)s)'</code>. If only the
+
<dd><p>默认为 <code>%(expression)s OVER (%(window)s)'</code>。 如果仅提供 <code>expression</code> 参数,则 window 子句将为空白。</p></dd></dl>
<code>expression</code> argument is provided, the window clause will be blank.</p></dd></dl>
 
 
</dd></dl>
 
</dd></dl>
  
The <code>Window</code> class is the main expression for an <code>OVER</code> clause.
+
<code>Window</code> 类是 <code>OVER</code> 子句的主要表达式。
  
The <code>expression</code> argument is either a [[../database-functions#window-functions|<span class="std std-ref">window function</span>]], an [[../querysets#aggregation-functions|<span class="std std-ref">aggregate function</span>]], or
+
<code>expression</code> 参数是 [[../database-functions#window-functions|窗口函数]] [[../querysets#aggregation-functions|聚合函数]] 或与窗口子句兼容的表达式。
an expression that's compatible in a window clause.
 
  
The <code>partition_by</code> argument is a list of expressions (column names should be
+
<code>partition_by</code> 参数是控制行分区的表达式列表(列名应包含在 <code>F</code> 对象中)。 分区缩小了用于计算结果集的行。
wrapped in an <code>F</code>-object) that control the partitioning of the rows.
 
Partitioning narrows which rows are used to compute the result set.
 
  
The <code>output_field</code> is specified either as an argument or by the expression.
+
<code>output_field</code> 被指定为参数或表达式。
  
The <code>order_by</code> argument accepts a sequence of expressions on which you can
+
<code>order_by</code> 参数接受一系列表达式,您可以在这些表达式上调用 [[#django.db.models.Expression.asc|asc()]] [[#django.db.models.Expression.desc|desc()]]。 排序控制应用表达式的顺序。 例如,如果对分区中的行求和,第一个结果就是第一行的值,第二个结果是第一行和第二行的总和。
call [[#django.db.models.Expression.asc|<code>asc()</code>]] and
 
[[#django.db.models.Expression.desc|<code>desc()</code>]]. The ordering controls the order in
 
which the expression is applied. For example, if you sum over the rows in a
 
partition, the first result is just the value of the first row, the second is
 
the sum of first and second row.
 
  
The <code>frame</code> parameter specifies which other rows that should be used in the
+
<code>frame</code> 参数指定应在计算中使用的其他行。 有关详细信息,请参阅 [[#window-frames|]]
computation. See [[#window-frames|<span class="std std-ref">Frames</span>]] for details.
 
  
For example, to annotate each movie with the average rating for the movies by
+
例如,要使用同一工作室、同一类型和发行年份的电影的平均评分来注释每部电影:
the same studio in the same genre and release year:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第1,040行: 第850行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; from django.db.models import Avg, F, Window
+
<syntaxhighlight lang="python">>>> from django.db.models import Avg, F, Window
&gt;&gt;&gt; from django.db.models.functions import ExtractYear
+
>>> from django.db.models.functions import ExtractYear
&gt;&gt;&gt; Movie.objects.annotate(
+
>>> Movie.objects.annotate(
&gt;&gt;&gt;     avg_rating=Window(
+
>>>     avg_rating=Window(
&gt;&gt;&gt;         expression=Avg('rating'),
+
>>>         expression=Avg('rating'),
&gt;&gt;&gt;         partition_by=[F('studio'), F('genre')],
+
>>>         partition_by=[F('studio'), F('genre')],
&gt;&gt;&gt;         order_by=ExtractYear('released').asc(),
+
>>>         order_by=ExtractYear('released').asc(),
&gt;&gt;&gt;     ),
+
>>>     ),
&gt;&gt;&gt; )</pre>
+
>>> )</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
This makes it easy to check if a movie is rated better or worse than its peers.
+
这可以让你检查一部电影的评分是好是坏,与它的同行相比。
  
You may want to apply multiple expressions over the same window, i.e., the
+
您可能希望在同一个窗口(即同一个分区和框架)上应用多个表达式。 例如,您可以修改前面的示例,通过在同一查询中使用三个窗口函数,还包括每个电影组(相同的工作室、流派和发行年份)中的最佳和最差评级。 将上一个示例中的分区和排序提取到字典中以减少重复:
same partition and frame. For example, you could modify the previous example
 
to also include the best and worst rating in each movie's group (same studio,
 
genre, and release year) by using three window functions in the same query. The
 
partition and ordering from the previous example is extracted into a dictionary
 
to reduce repetition:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第1,066行: 第871行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; from django.db.models import Avg, F, Max, Min, Window
+
<syntaxhighlight lang="python">>>> from django.db.models import Avg, F, Max, Min, Window
&gt;&gt;&gt; from django.db.models.functions import ExtractYear
+
>>> from django.db.models.functions import ExtractYear
&gt;&gt;&gt; window = {
+
>>> window = {
&gt;&gt;&gt;   'partition_by': [F('studio'), F('genre')],
+
>>>   'partition_by': [F('studio'), F('genre')],
&gt;&gt;&gt;   'order_by': ExtractYear('released').asc(),
+
>>>   'order_by': ExtractYear('released').asc(),
&gt;&gt;&gt; }
+
>>> }
&gt;&gt;&gt; Movie.objects.annotate(
+
>>> Movie.objects.annotate(
&gt;&gt;&gt;     avg_rating=Window(
+
>>>     avg_rating=Window(
&gt;&gt;&gt;         expression=Avg('rating'), **window,
+
>>>         expression=Avg('rating'), **window,
&gt;&gt;&gt;     ),
+
>>>     ),
&gt;&gt;&gt;     best=Window(
+
>>>     best=Window(
&gt;&gt;&gt;         expression=Max('rating'), **window,
+
>>>         expression=Max('rating'), **window,
&gt;&gt;&gt;     ),
+
>>>     ),
&gt;&gt;&gt;     worst=Window(
+
>>>     worst=Window(
&gt;&gt;&gt;         expression=Min('rating'), **window,
+
>>>         expression=Min('rating'), **window,
&gt;&gt;&gt;     ),
+
>>>     ),
&gt;&gt;&gt; )</pre>
+
>>> )</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Among Django's built-in database backends, MySQL 8.0.2+, PostgreSQL, and Oracle
+
Django 的内置数据库后端中,MySQL 8.0.2+、PostgreSQL 和 Oracle 支持窗口表达式。 对不同窗口表达式功能的支持因数据库而异。 例如,可能不支持 [[#django.db.models.Expression.asc|asc()]] [[#django.db.models.Expression.desc|desc()]] 中的选项。 根据需要查阅您的数据库的文档。
support window expressions. Support for different window expression features
 
varies among the different databases. For example, the options in
 
[[#django.db.models.Expression.asc|<code>asc()</code>]] and
 
[[#django.db.models.Expression.desc|<code>desc()</code>]] may not be supported. Consult the
 
documentation for your database as needed.
 
  
 
<div id="frames" class="section">
 
<div id="frames" class="section">
  
 
<span id="window-frames"></span>
 
<span id="window-frames"></span>
==== Frames ====
+
==== ====
  
For a window frame, you can choose either a range-based sequence of rows or an
+
对于一个窗口帧,你可以选择基于范围的行序列或普通的行序列。
ordinary sequence of rows.
 
  
 
<dl>
 
<dl>
<dt>''class'' <code>ValueRange</code><span class="sig-paren">(</span>''<span class="n">start</span><span class="o">=</span><span class="default_value">None</span>'', ''<span class="n">end</span><span class="o">=</span><span class="default_value">None</span>''<span class="sig-paren">)</span>[[../../_modules/django/db/models/expressions.html#ValueRange|<span class="viewcode-link">[源代码]</span>]]</dt>
+
<dt>''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">ValueRange</span></span><span class="sig-paren">(</span>''<span class="n"><span class="pre">start</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span>'', ''<span class="n"><span class="pre">end</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span>''<span class="sig-paren">)</span></dt>
 
<dd><dl>
 
<dd><dl>
<dt><code>frame_type</code></dt>
+
<dt><span class="sig-name descname"><span class="pre">frame_type</span></span></dt>
<dd><p>This attribute is set to <code>'RANGE'</code>.</p></dd></dl>
+
<dd><p>此属性设置为 <code>'RANGE'</code></p></dd></dl>
  
<p>PostgreSQL has limited support for <code>ValueRange</code> and only supports use of
+
<p>PostgreSQL <code>ValueRange</code> 的支持有限,只支持使用标准的起点和终点,例如 <code>CURRENT ROW</code> <code>UNBOUNDED FOLLOWING</code></p></dd></dl>
the standard start and end points, such as <code>CURRENT ROW</code> and <code>UNBOUNDED FOLLOWING</code>.</p></dd></dl>
 
  
; ''class'' <code>RowRange</code><span class="sig-paren">(</span>''<span class="n">start</span><span class="o">=</span><span class="default_value">None</span>'', ''<span class="n">end</span><span class="o">=</span><span class="default_value">None</span>''<span class="sig-paren">)</span>[[../../_modules/django/db/models/expressions.html#RowRange|<span class="viewcode-link">[源代码]</span>]]
+
; ''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">RowRange</span></span><span class="sig-paren">(</span>''<span class="n"><span class="pre">start</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span>'', ''<span class="n"><span class="pre">end</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span>''<span class="sig-paren">)</span>
: ;; <code>frame_type</code>
+
: ;; <span class="sig-name descname"><span class="pre">frame_type</span></span>
;: This attribute is set to <code>'ROWS'</code>.
+
;: 此属性设置为 <code>'ROWS'</code>
  
Both classes return SQL with the template:
+
这两个类都返回带有模板的 SQL:
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第1,121行: 第919行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>%(frame_type)s BETWEEN %(start)s AND %(end)s</pre>
+
<syntaxhighlight lang="python">%(frame_type)s BETWEEN %(start)s AND %(end)s</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Frames narrow the rows that are used for computing the result. They shift from
+
框架缩小了用于计算结果的行。 它们从某个起点转移到某个指定的终点。 框架可以使用和不使用分区,但指定窗口的顺序以确保确定性结果通常是个好主意。 在框架中,框架中的对等点是具有等效值的行,或者如果不存在排序子句,则是所有行。
some start point to some specified end point. Frames can be used with and
 
without partitions, but it's often a good idea to specify an ordering of the
 
window to ensure a deterministic result. In a frame, a peer in a frame is a row
 
with an equivalent value, or all rows if an ordering clause isn't present.
 
  
The default starting point for a frame is <code>UNBOUNDED PRECEDING</code> which is the
+
帧的默认起点是 <code>UNBOUNDED PRECEDING</code>,它是分区的第一行。 终点始终明确包含在 ORM 生成的 SQL 中,默认情况下为 <code>UNBOUNDED FOLLOWING</code>。 默认框架包括从分区到集合中最后一行的所有行。
first row of the partition. The end point is always explicitly included in the
 
SQL generated by the ORM and is by default <code>UNBOUNDED FOLLOWING</code>. The default
 
frame includes all rows from the partition to the last row in the set.
 
  
The accepted values for the <code>start</code> and <code>end</code> arguments are <code>None</code>, an
+
<code>start</code> <code>end</code> 参数的可接受值为 <code>None</code>、整数或零。 <code>start</code> 的负整数产生 <code>N preceding</code>,而 <code>None</code> 产生 <code>UNBOUNDED PRECEDING</code>。 对于 <code>start</code> <code>end</code>,零将返回 <code>CURRENT ROW</code><code>end</code> 接受正整数。
integer, or zero. A negative integer for <code>start</code> results in <code>N preceding</code>,
 
while <code>None</code> yields <code>UNBOUNDED PRECEDING</code>. For both <code>start</code> and <code>end</code>,
 
zero will return <code>CURRENT ROW</code>. Positive integers are accepted for <code>end</code>.
 
  
There's a difference in what <code>CURRENT ROW</code> includes. When specified in
+
<code>CURRENT ROW</code> 包含的内容有所不同。 在 <code>ROWS</code> 模式下指定时,帧以当前行开始或结束。 当在 <code>RANGE</code> 模式下指定时,帧根据排序条款在第一个或最后一个对等点开始或结束。 因此,<code>RANGE CURRENT ROW</code> 为具有由排序指定的相同值的行计算表达式。 因为模板同时包含 <code>start</code> <code>end</code> 点,这可以表示为:
<code>ROWS</code> mode, the frame starts or ends with the current row. When specified in
 
<code>RANGE</code> mode, the frame starts or ends at the first or last peer according to
 
the ordering clause. Thus, <code>RANGE CURRENT ROW</code> evaluates the expression for
 
rows which have the same value specified by the ordering. Because the template
 
includes both the <code>start</code> and <code>end</code> points, this may be expressed with:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第1,153行: 第936行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>ValueRange(start=0, end=0)</pre>
+
<syntaxhighlight lang="python">ValueRange(start=0, end=0)</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
If a movie's &quot;peers&quot; are described as movies released by the same studio in the
+
如果一部电影的“同行”被描述为同一年同一类型的同一工作室发行的电影,这个 <code>RowRange</code> 示例用电影的两个前两个同行和两个后续同行的平均评分来注释每部电影:
same genre in the same year, this <code>RowRange</code> example annotates each movie
 
with the average rating of a movie's two prior and two following peers:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第1,166行: 第947行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; from django.db.models import Avg, F, RowRange, Window
+
<syntaxhighlight lang="python">>>> from django.db.models import Avg, F, RowRange, Window
&gt;&gt;&gt; from django.db.models.functions import ExtractYear
+
>>> from django.db.models.functions import ExtractYear
&gt;&gt;&gt; Movie.objects.annotate(
+
>>> Movie.objects.annotate(
&gt;&gt;&gt;     avg_rating=Window(
+
>>>     avg_rating=Window(
&gt;&gt;&gt;         expression=Avg('rating'),
+
>>>         expression=Avg('rating'),
&gt;&gt;&gt;         partition_by=[F('studio'), F('genre')],
+
>>>         partition_by=[F('studio'), F('genre')],
&gt;&gt;&gt;         order_by=ExtractYear('released').asc(),
+
>>>         order_by=ExtractYear('released').asc(),
&gt;&gt;&gt;         frame=RowRange(start=-2, end=2),
+
>>>         frame=RowRange(start=-2, end=2),
&gt;&gt;&gt;     ),
+
>>>     ),
&gt;&gt;&gt; )</pre>
+
>>> )</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
If the database supports it, you can specify the start and end points based on
+
如果数据库支持,您可以根据分区中表达式的值指定起点和终点。 如果 <code>Movie</code> 模型的 <code>released</code> 字段存储每部电影的发行月份,则此 <code>ValueRange</code> 示例使用在前 12 个月之间发行的电影同行的平均评分来注释每部电影每部电影后十二个月。
values of an expression in the partition. If the <code>released</code> field of the
 
<code>Movie</code> model stores the release month of each movies, this <code>ValueRange</code>
 
example annotates each movie with the average rating of a movie's peers
 
released between twelve months before and twelve months after the each movie.
 
  
 
<div class="doctest highlight-default notranslate">
 
<div class="doctest highlight-default notranslate">
第1,190行: 第967行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; from django.db.models import Avg, ExpressionList, F, ValueRange, Window
+
<syntaxhighlight lang="python">>>> from django.db.models import Avg, ExpressionList, F, ValueRange, Window
&gt;&gt;&gt; Movie.objects.annotate(
+
>>> Movie.objects.annotate(
&gt;&gt;&gt;     avg_rating=Window(
+
>>>     avg_rating=Window(
&gt;&gt;&gt;         expression=Avg('rating'),
+
>>>         expression=Avg('rating'),
&gt;&gt;&gt;         partition_by=[F('studio'), F('genre')],
+
>>>         partition_by=[F('studio'), F('genre')],
&gt;&gt;&gt;         order_by=F('released').asc(),
+
>>>         order_by=F('released').asc(),
&gt;&gt;&gt;         frame=ValueRange(start=-12, end=12),
+
>>>         frame=ValueRange(start=-12, end=12),
&gt;&gt;&gt;     ),
+
>>>     ),
&gt;&gt;&gt; )</pre>
+
>>> )</syntaxhighlight>
  
 
</div>
 
</div>
第1,211行: 第988行:
 
<div id="technical-information" class="section">
 
<div id="technical-information" class="section">
  
== Technical Information ==
+
== 技术信息 ==
  
Below you'll find technical implementation details that may be useful to
+
您将在下面找到可能对库作者有用的技术实现细节。 下面的技术 API 和示例将有助于创建可以扩展 Django 提供的内置功能的通用查询表达式。
library authors. The technical API and examples below will help with
 
creating generic query expressions that can extend the built-in functionality
 
that Django provides.
 
  
 
<div id="expression-api" class="section">
 
<div id="expression-api" class="section">
  
=== Expression API ===
+
=== 表达式 API ===
  
Query expressions implement the [[../lookups#query-expression|<span class="std std-ref">query expression API</span>]],
+
查询表达式实现了 [[../lookups#query-expression|查询表达式 API]],但也公开了下面列出的许多额外方法和属性。 所有查询表达式都必须从 <code>Expression()</code> 或相关子类继承。
but also expose a number of extra methods and attributes listed below. All
 
query expressions must inherit from <code>Expression()</code> or a relevant
 
subclass.
 
  
When a query expression wraps another expression, it is responsible for
+
当一个查询表达式包装另一个表达式时,它负责在被包装的表达式上调用相应的方法。
calling the appropriate methods on the wrapped expression.
 
  
 
<dl>
 
<dl>
<dt>''class'' <code>Expression</code>[[../../_modules/django/db/models/expressions.html#Expression|<span class="viewcode-link">[源代码]</span>]]</dt>
+
<dt>''<span class="pre">class</span>'' <span class="sig-name descname"><span class="pre">Expression</span></span></dt>
 
<dd><dl>
 
<dd><dl>
<dt><code>contains_aggregate</code></dt>
+
<dt><span class="sig-name descname"><span class="pre">contains_aggregate</span></span></dt>
<dd><p>Tells Django that this expression contains an aggregate and that a
+
<dd><p>告诉 Django 这个表达式包含一个聚合并且需要将 <code>GROUP BY</code> 子句添加到查询中。</p></dd></dl>
<code>GROUP BY</code> clause needs to be added to the query.</p></dd></dl>
 
  
 
<dl>
 
<dl>
<dt><code>contains_over_clause</code></dt>
+
<dt><span class="sig-name descname"><span class="pre">contains_over_clause</span></span></dt>
<dd><p>Tells Django that this expression contains a
+
<dd><p>告诉 Django 这个表达式包含一个 [[#django.db.models.expressions.Window|Window]] 表达式。 例如,它用于在修改数据的查询中禁止窗口函数表达式。</p></dd></dl>
[[#django.db.models.expressions.Window|<code>Window</code>]] expression. It's used,
 
for example, to disallow window function expressions in queries that
 
modify data.</p></dd></dl>
 
  
 
<dl>
 
<dl>
<dt><code>filterable</code></dt>
+
<dt><span class="sig-name descname"><span class="pre">filterable</span></span></dt>
<dd><p>Tells Django that this expression can be referenced in
+
<dd><p>告诉 Django 这个表达式可以在 [[../querysets#django.db.models.query.QuerySet|QuerySet.filter()]] 中引用。 默认为 <code>True</code></p></dd></dl>
[[../querysets#django.db.models.query.QuerySet|<code>QuerySet.filter()</code>]]. Defaults to <code>True</code>.</p></dd></dl>
 
  
 
<dl>
 
<dl>
<dt><code>window_compatible</code></dt>
+
<dt><span class="sig-name descname"><span class="pre">window_compatible</span></span></dt>
<dd><p>Tells Django that this expression can be used as the source expression
+
<dd><p>告诉 Django 这个表达式可以用作 [[#django.db.models.expressions.Window|Window]] 中的源表达式。 默认为 <code>False</code></p></dd></dl>
in [[#django.db.models.expressions.Window|<code>Window</code>]]. Defaults to
 
<code>False</code>.</p></dd></dl>
 
  
 
<dl>
 
<dl>
<dt><code>resolve_expression</code><span class="sig-paren">(</span>''<span class="n">query</span><span class="o">=</span><span class="default_value">None</span>'', ''<span class="n">allow_joins</span><span class="o">=</span><span class="default_value">True</span>'', ''<span class="n">reuse</span><span class="o">=</span><span class="default_value">None</span>'', ''<span class="n">summarize</span><span class="o">=</span><span class="default_value">False</span>'', ''<span class="n">for_save</span><span class="o">=</span><span class="default_value">False</span>''<span class="sig-paren">)</span></dt>
+
<dt><span class="sig-name descname"><span class="pre">resolve_expression</span></span><span class="sig-paren">(</span>''<span class="n"><span class="pre">query</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span>'', ''<span class="n"><span class="pre">allow_joins</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">True</span></span>'', ''<span class="n"><span class="pre">reuse</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span>'', ''<span class="n"><span class="pre">summarize</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span>'', ''<span class="n"><span class="pre">for_save</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span>''<span class="sig-paren">)</span></dt>
<dd><p>Provides the chance to do any pre-processing or validation of
+
<dd><p>提供在将表达式添加到查询之前对其进行任何预处理或验证的机会。 <code>resolve_expression()</code> 也必须在任何嵌套表达式上调用。 <code>self</code> <code>copy()</code> 应与任何必要的转换一起返回。</p>
the expression before it's added to the query. <code>resolve_expression()</code>
+
<p><code>query</code> 是后端查询实现。</p>
must also be called on any nested expressions. A <code>copy()</code> of <code>self</code>
+
<p><code>allow_joins</code> 是一个布尔值,允许或拒绝在查询中使用连接。</p>
should be returned with any necessary transformations.</p>
+
<p><code>reuse</code> 是一组用于多连接场景的可重用连接。</p>
<p><code>query</code> is the backend query implementation.</p>
+
<p><code>summarize</code> 是一个布尔值,当 <code>True</code> 表示正在计算的查询是终端聚合查询时。</p>
<p><code>allow_joins</code> is a boolean that allows or denies the use of
+
<p><code>for_save</code> 是一个布尔值,当 <code>True</code> 时,表示正在执行的查询正在执行创建或更新。</p></dd></dl>
joins in the query.</p>
 
<p><code>reuse</code> is a set of reusable joins for multi-join scenarios.</p>
 
<p><code>summarize</code> is a boolean that, when <code>True</code>, signals that the
 
query being computed is a terminal aggregate query.</p>
 
<p><code>for_save</code> is a boolean that, when <code>True</code>, signals that the query
 
being executed is performing a create or update.</p></dd></dl>
 
  
 
<dl>
 
<dl>
<dt><code>get_source_expressions</code><span class="sig-paren">(</span><span class="sig-paren">)</span></dt>
+
<dt><span class="sig-name descname"><span class="pre">get_source_expressions</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span></dt>
<dd><p>Returns an ordered list of inner expressions. For example:</p>
+
<dd><p>返回内部表达式的有序列表。 例如:</p>
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
  
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; Sum(F('foo')).get_source_expressions()
+
<syntaxhighlight lang="python">>>> Sum(F('foo')).get_source_expressions()
[F('foo')]</pre>
+
[F('foo')]</syntaxhighlight>
  
 
</div>
 
</div>
第1,285行: 第1,042行:
  
 
<dl>
 
<dl>
<dt><code>set_source_expressions</code><span class="sig-paren">(</span>''<span class="n">expressions</span>''<span class="sig-paren">)</span></dt>
+
<dt><span class="sig-name descname"><span class="pre">set_source_expressions</span></span><span class="sig-paren">(</span>''<span class="n"><span class="pre">expressions</span></span>''<span class="sig-paren">)</span></dt>
<dd><p>Takes a list of expressions and stores them such that
+
<dd><p>获取表达式列表并存储它们,以便 <code>get_source_expressions()</code> 可以返回它们。</p></dd></dl>
<code>get_source_expressions()</code> can return them.</p></dd></dl>
 
  
 
<dl>
 
<dl>
<dt><code>relabeled_clone</code><span class="sig-paren">(</span>''<span class="n">change_map</span>''<span class="sig-paren">)</span></dt>
+
<dt><span class="sig-name descname"><span class="pre">relabeled_clone</span></span><span class="sig-paren">(</span>''<span class="n"><span class="pre">change_map</span></span>''<span class="sig-paren">)</span></dt>
<dd><p>Returns a clone (copy) of <code>self</code>, with any column aliases relabeled.
+
<dd><p>返回 <code>self</code> 的克隆(副本),并重新标记任何列别名。 创建子查询时,列别名会被重命名。 <code>relabeled_clone()</code> 也应该在任何嵌套表达式上调用并分配给克隆。</p>
Column aliases are renamed when subqueries are created.
+
<p><code>change_map</code> 是一个将旧别名映射到新别名的字典。</p>
<code>relabeled_clone()</code> should also be called on any nested expressions
+
<p>例子:</p>
and assigned to the clone.</p>
 
<p><code>change_map</code> is a dictionary mapping old aliases to new aliases.</p>
 
<p>举例:</p>
 
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
  
 
<div class="highlight">
 
<div class="highlight">
  
<pre>def relabeled_clone(self, change_map):
+
<syntaxhighlight lang="python">def relabeled_clone(self, change_map):
 
     clone = copy.copy(self)
 
     clone = copy.copy(self)
 
     clone.expression = self.expression.relabeled_clone(change_map)
 
     clone.expression = self.expression.relabeled_clone(change_map)
     return clone</pre>
+
     return clone</syntaxhighlight>
  
 
</div>
 
</div>
第1,311行: 第1,064行:
  
 
<dl>
 
<dl>
<dt><code>convert_value</code><span class="sig-paren">(</span>''<span class="n">value</span>'', ''<span class="n">expression</span>'', ''<span class="n">connection</span>''<span class="sig-paren">)</span></dt>
+
<dt><span class="sig-name descname"><span class="pre">convert_value</span></span><span class="sig-paren">(</span>''<span class="n"><span class="pre">value</span></span>'', ''<span class="n"><span class="pre">expression</span></span>'', ''<span class="n"><span class="pre">connection</span></span>''<span class="sig-paren">)</span></dt>
<dd><p>A hook allowing the expression to coerce <code>value</code> into a more
+
<dd><p>一个钩子,允许表达式将 <code>value</code> 强制转换为更合适的类型。</p></dd></dl>
appropriate type.</p></dd></dl>
 
  
 
<dl>
 
<dl>
<dt><code>get_group_by_cols</code><span class="sig-paren">(</span><span class="sig-paren">)</span></dt>
+
<dt><span class="sig-name descname"><span class="pre">get_group_by_cols</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span></dt>
<dd><p>Responsible for returning the list of columns references by
+
<dd><p>负责通过此表达式返回列引用列表。 <code>get_group_by_cols()</code> 应该在任何嵌套表达式上调用。 <code>F()</code> 对象,特别是,持有对列的引用。</p></dd></dl>
this expression. <code>get_group_by_cols()</code> should be called on any
 
nested expressions. <code>F()</code> objects, in particular, hold a reference
 
to a column.</p></dd></dl>
 
  
 
<dl>
 
<dl>
<dt><code>asc</code><span class="sig-paren">(</span>''<span class="n">nulls_first</span><span class="o">=</span><span class="default_value">False</span>'', ''<span class="n">nulls_last</span><span class="o">=</span><span class="default_value">False</span>''<span class="sig-paren">)</span></dt>
+
<dt><span class="sig-name descname"><span class="pre">asc</span></span><span class="sig-paren">(</span>''<span class="n"><span class="pre">nulls_first</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span>'', ''<span class="n"><span class="pre">nulls_last</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span>''<span class="sig-paren">)</span></dt>
<dd><p>Returns the expression ready to be sorted in ascending order.</p>
+
<dd><p>返回准备按升序排序的表达式。</p>
<p><code>nulls_first</code> and <code>nulls_last</code> define how null values are sorted.
+
<p><code>nulls_first</code> <code>nulls_last</code> 定义空值的排序方式。 请参阅 [[#using-f-to-sort-null-values|使用 F() 对空值进行排序]] 以获取示例用法。</p></dd></dl>
See [[#using-f-to-sort-null-values|<span class="std std-ref">Using F() to sort null values</span>]] for example usage.</p></dd></dl>
 
  
 
<dl>
 
<dl>
<dt><code>desc</code><span class="sig-paren">(</span>''<span class="n">nulls_first</span><span class="o">=</span><span class="default_value">False</span>'', ''<span class="n">nulls_last</span><span class="o">=</span><span class="default_value">False</span>''<span class="sig-paren">)</span></dt>
+
<dt><span class="sig-name descname"><span class="pre">desc</span></span><span class="sig-paren">(</span>''<span class="n"><span class="pre">nulls_first</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span>'', ''<span class="n"><span class="pre">nulls_last</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span>''<span class="sig-paren">)</span></dt>
<dd><p>Returns the expression ready to be sorted in descending order.</p>
+
<dd><p>返回准备好降序排序的表达式。</p>
<p><code>nulls_first</code> and <code>nulls_last</code> define how null values are sorted.
+
<p><code>nulls_first</code> <code>nulls_last</code> 定义空值的排序方式。 请参阅 [[#using-f-to-sort-null-values|使用 F() 对空值进行排序]] 以获取示例用法。</p></dd></dl>
See [[#using-f-to-sort-null-values|<span class="std std-ref">Using F() to sort null values</span>]] for example usage.</p></dd></dl>
 
  
 
<dl>
 
<dl>
<dt><code>reverse_ordering</code><span class="sig-paren">(</span><span class="sig-paren">)</span></dt>
+
<dt><span class="sig-name descname"><span class="pre">reverse_ordering</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span></dt>
<dd><p>Returns <code>self</code> with any modifications required to reverse the sort
+
<dd><p>返回 <code>self</code> 以及在 <code>order_by</code> 调用中反转排序顺序所需的任何修改。 例如,实现 <code>NULLS LAST</code> 的表达式会将其值更改为 <code>NULLS FIRST</code>。 只有实现排序顺序的表达式(如 <code>OrderBy</code>)才需要修改。 当在查询集上调用 [[../querysets#django.db.models.query.QuerySet|reverse()]] 时调用此方法。</p></dd></dl>
order within an <code>order_by</code> call. As an example, an expression
 
implementing <code>NULLS LAST</code> would change its value to be
 
<code>NULLS FIRST</code>. Modifications are only required for expressions that
 
implement sort order like <code>OrderBy</code>. This method is called when
 
[[../querysets#django.db.models.query.QuerySet|<code>reverse()</code>]] is called on a
 
queryset.</p></dd></dl>
 
 
</dd></dl>
 
</dd></dl>
  
第1,349行: 第1,090行:
 
<div id="writing-your-own-query-expressions" class="section">
 
<div id="writing-your-own-query-expressions" class="section">
  
=== Writing your own Query Expressions ===
+
=== 编写自己的查询表达式 ===
  
You can write your own query expression classes that use, and can integrate
+
您可以编写自己的查询表达式类,这些类使用并可以与其他查询表达式集成。 让我们通过编写 <code>COALESCE</code> SQL 函数的实现来逐步完成一个示例,而不使用内置的 [[#func-expressions|Func() 表达式]]
with, other query expressions. Let's step through an example by writing an
 
implementation of the <code>COALESCE</code> SQL function, without using the built-in
 
[[#func-expressions|<span class="std std-ref">Func() expressions</span>]].
 
  
The <code>COALESCE</code> SQL function is defined as taking a list of columns or
+
<code>COALESCE</code> SQL 函数被定义为获取列或值的列表。 它将返回不是 <code>NULL</code> 的第一列或值。
values. It will return the first column or value that isn't <code>NULL</code>.
 
  
We'll start by defining the template to be used for SQL generation and
+
我们将首先定义用于 SQL 生成的模板和一个 <code>__init__()</code> 方法来设置一些属性:
an <code>__init__()</code> method to set some attributes:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第1,366行: 第1,102行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>import copy
+
<syntaxhighlight lang="python">import copy
 
from django.db.models import Expression
 
from django.db.models import Expression
  
第1,374行: 第1,110行:
 
     def __init__(self, expressions, output_field):
 
     def __init__(self, expressions, output_field):
 
       super().__init__(output_field=output_field)
 
       super().__init__(output_field=output_field)
       if len(expressions) &lt; 2:
+
       if len(expressions) < 2:
 
           raise ValueError('expressions must have at least 2 elements')
 
           raise ValueError('expressions must have at least 2 elements')
 
       for expression in expressions:
 
       for expression in expressions:
 
           if not hasattr(expression, 'resolve_expression'):
 
           if not hasattr(expression, 'resolve_expression'):
 
               raise TypeError('%r is not an Expression' % expression)
 
               raise TypeError('%r is not an Expression' % expression)
       self.expressions = expressions</pre>
+
       self.expressions = expressions</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
We do some basic validation on the parameters, including requiring at least
+
我们对参数进行了一些基本验证,包括要求至少有 2 个列或值,并确保它们是表达式。 我们在这里要求 <code>output_field</code> 以便 Django 知道将最终结果分配给什么样的模型字段。
2 columns or values, and ensuring they are expressions. We are requiring
 
<code>output_field</code> here so that Django knows what kind of model field to assign
 
the eventual result to.
 
  
Now we implement the pre-processing and validation. Since we do not have
+
现在我们实现预处理和验证。 由于此时我们没有任何自己的验证,我们只委托给嵌套表达式:
any of our own validation at this point, we just delegate to the nested
 
expressions:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第1,397行: 第1,128行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>def resolve_expression(self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False):
+
<syntaxhighlight lang="python">def resolve_expression(self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False):
 
     c = self.copy()
 
     c = self.copy()
 
     c.is_summary = summarize
 
     c.is_summary = summarize
 
     for pos, expression in enumerate(self.expressions):
 
     for pos, expression in enumerate(self.expressions):
 
         c.expressions[pos] = expression.resolve_expression(query, allow_joins, reuse, summarize, for_save)
 
         c.expressions[pos] = expression.resolve_expression(query, allow_joins, reuse, summarize, for_save)
     return c</pre>
+
     return c</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Next, we write the method responsible for generating the SQL:
+
接下来,我们编写负责生成 SQL 的方法:
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第1,413行: 第1,144行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>def as_sql(self, compiler, connection, template=None):
+
<syntaxhighlight lang="python">def as_sql(self, compiler, connection, template=None):
 
     sql_expressions, sql_params = [], []
 
     sql_expressions, sql_params = [], []
 
     for expression in self.expressions:
 
     for expression in self.expressions:
第1,424行: 第1,155行:
  
 
def as_oracle(self, compiler, connection):
 
def as_oracle(self, compiler, connection):
     &quot;&quot;&quot;
+
     """
 
     Example of vendor specific handling (Oracle in this case).
 
     Example of vendor specific handling (Oracle in this case).
 
     Let's make the function name lowercase.
 
     Let's make the function name lowercase.
     &quot;&quot;&quot;
+
     """
     return self.as_sql(compiler, connection, template='coalesce( %(expressions)s )')</pre>
+
     return self.as_sql(compiler, connection, template='coalesce( %(expressions)s )')</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
<code>as_sql()</code> methods can support custom keyword arguments, allowing
+
<code>as_sql()</code> 方法可以支持自定义关键字参数,允许 <code>as_vendorname()</code> 方法覆盖用于生成 SQL 字符串的数据。 使用 <code>as_sql()</code> 关键字参数进行自定义比在 <code>as_vendorname()</code> 方法中改变 <code>self</code> 更可取,因为后者在不同的数据库后端上运行时会导致错误。 如果您的类依赖类属性来定义数据,请考虑在您的 <code>as_sql()</code> 方法中允许覆盖。
<code>as_vendorname()</code> methods to override data used to generate the SQL string.
 
Using <code>as_sql()</code> keyword arguments for customization is preferable to
 
mutating <code>self</code> within <code>as_vendorname()</code> methods as the latter can lead to
 
errors when running on different database backends. If your class relies on
 
class attributes to define data, consider allowing overrides in your
 
<code>as_sql()</code> method.
 
  
We generate the SQL for each of the <code>expressions</code> by using the
+
我们使用 <code>compiler.compile()</code> 方法为每个 <code>expressions</code> 生成 SQL,并将结果用逗号连接在一起。 然后用我们的数据填充模板,并返回 SQL 和参数。
<code>compiler.compile()</code> method, and join the result together with commas.
 
Then the template is filled out with our data and the SQL and parameters
 
are returned.
 
  
We've also defined a custom implementation that is specific to the Oracle
+
我们还定义了一个特定于 Oracle 后端的自定义实现。 如果使用 Oracle 后端,将调用 <code>as_oracle()</code> 函数而不是 <code>as_sql()</code>
backend. The <code>as_oracle()</code> function will be called instead of <code>as_sql()</code>
 
if the Oracle backend is in use.
 
  
Finally, we implement the rest of the methods that allow our query expression
+
最后,我们实现了其余的方法,使我们的查询表达式可以与其他查询表达式配合使用:
to play nice with other query expressions:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第1,457行: 第1,176行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>def get_source_expressions(self):
+
<syntaxhighlight lang="python">def get_source_expressions(self):
 
     return self.expressions
 
     return self.expressions
  
 
def set_source_expressions(self, expressions):
 
def set_source_expressions(self, expressions):
     self.expressions = expressions</pre>
+
     self.expressions = expressions</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
Let's see how it works:
+
让我们看看它是如何工作的:
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第1,472行: 第1,191行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>&gt;&gt;&gt; from django.db.models import F, Value, CharField
+
<syntaxhighlight lang="python">>>> from django.db.models import F, Value, CharField
&gt;&gt;&gt; qs = Company.objects.annotate(
+
>>> qs = Company.objects.annotate(
 
...    tagline=Coalesce([
 
...    tagline=Coalesce([
 
...        F('motto'),
 
...        F('motto'),
第1,480行: 第1,199行:
 
...        Value('No Tagline')
 
...        Value('No Tagline')
 
...        ], output_field=CharField()))
 
...        ], output_field=CharField()))
&gt;&gt;&gt; for c in qs:
+
>>> for c in qs:
...    print(&quot;%s: %s&quot; % (c.name, c.tagline))
+
...    print("%s: %s" % (c.name, c.tagline))
 
...
 
...
 
Google: Do No Evil
 
Google: Do No Evil
 
Apple: AAPL
 
Apple: AAPL
 
Yahoo: Internet Company
 
Yahoo: Internet Company
Django Software Foundation: No Tagline</pre>
+
Django Software Foundation: No Tagline</syntaxhighlight>
  
 
</div>
 
</div>
第1,494行: 第1,213行:
  
 
<span id="avoiding-sql-injection-in-query-expressions"></span>
 
<span id="avoiding-sql-injection-in-query-expressions"></span>
==== Avoiding SQL injection ====
+
==== 避免 SQL 注入 ====
  
Since a <code>Func</code>'s keyword arguments for <code>__init__()</code> (<code>**extra</code>) and
+
由于 <code>__init__()</code> (<code>**extra</code>) <code>as_sql()</code> (<code>**extra_context</code>) 的 <code>Func</code> 的关键字参数被插入到 SQL 字符串中而不是作为查询参数传递(数据库驱动程序将在其中转义它们),它们不能包含不受信任的用户输入。
<code>as_sql()</code> (<code>**extra_context</code>) are interpolated into the SQL string rather
 
than passed as query parameters (where the database driver would escape them),
 
they must not contain untrusted user input.
 
  
For example, if <code>substring</code> is user-provided, this function is vulnerable to
+
例如,如果 <code>substring</code> 是用户提供的,则此函数容易受到 SQL 注入:
SQL injection:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第1,508行: 第1,223行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>from django.db.models import Func
+
<syntaxhighlight lang="python">from django.db.models import Func
  
 
class Position(Func):
 
class Position(Func):
 
     function = 'POSITION'
 
     function = 'POSITION'
     template = &quot;%(function)s('%(substring)s' in %(expressions)s)&quot;
+
     template = "%(function)s('%(substring)s' in %(expressions)s)"
  
 
     def __init__(self, expression, substring):
 
     def __init__(self, expression, substring):
 
         # substring=substring is a SQL injection vulnerability!
 
         # substring=substring is a SQL injection vulnerability!
         super().__init__(expression, substring=substring)</pre>
+
         super().__init__(expression, substring=substring)</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
This function generates a SQL string without any parameters. Since <code>substring</code>
+
此函数生成不带任何参数的 SQL 字符串。 由于 <code>substring</code> 作为关键字参数传递给 <code>super().__init__()</code>,它在查询发送到数据库之前被插入到 SQL 字符串中。
is passed to <code>super().__init__()</code> as a keyword argument, it's interpolated
 
into the SQL string before the query is sent to the database.
 
  
Here's a corrected rewrite:
+
这是一个更正的重写:
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第1,531行: 第1,244行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>class Position(Func):
+
<syntaxhighlight lang="python">class Position(Func):
 
     function = 'POSITION'
 
     function = 'POSITION'
 
     arg_joiner = ' IN '
 
     arg_joiner = ' IN '
  
 
     def __init__(self, expression, substring):
 
     def __init__(self, expression, substring):
         super().__init__(substring, expression)</pre>
+
         super().__init__(substring, expression)</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
With <code>substring</code> instead passed as a positional argument, it'll be passed as
+
使用 <code>substring</code> 代替作为位置参数传递,它将作为数据库查询中的参数传递。
a parameter in the database query.
 
  
  
第1,550行: 第1,262行:
 
<div id="adding-support-in-third-party-database-backends" class="section">
 
<div id="adding-support-in-third-party-database-backends" class="section">
  
=== Adding support in third-party database backends ===
+
=== 在第三方数据库后端增加支持 ===
  
If you're using a database backend that uses a different SQL syntax for a
+
如果您使用的数据库后端对某个函数使用不同的 SQL 语法,您可以通过将新方法添加到函数的类上来添加对它的支持。
certain function, you can add support for it by monkey patching a new method
 
onto the function's class.
 
  
Let's say we're writing a backend for Microsoft's SQL Server which uses the SQL
+
假设我们正在为 Microsoft SQL Server 编写后端,它使用 SQL <code>LEN</code> 而不是 [[../database-functions#django.db.models.functions|Length]] 函数的 <code>LENGTH</code>。 我们将在 <code>Length</code> 类上添加一个名为 <code>as_sqlserver()</code> 的新方法:
<code>LEN</code> instead of <code>LENGTH</code> for the [[../database-functions#django.db.models.functions|<code>Length</code>]] function.
 
We'll monkey patch a new method called <code>as_sqlserver()</code> onto the <code>Length</code>
 
class:
 
  
 
<div class="highlight-default notranslate">
 
<div class="highlight-default notranslate">
第1,565行: 第1,272行:
 
<div class="highlight">
 
<div class="highlight">
  
<pre>from django.db.models.functions import Length
+
<syntaxhighlight lang="python">from django.db.models.functions import Length
  
 
def sqlserver_length(self, compiler, connection):
 
def sqlserver_length(self, compiler, connection):
 
     return self.as_sql(compiler, connection, function='LEN')
 
     return self.as_sql(compiler, connection, function='LEN')
  
Length.as_sqlserver = sqlserver_length</pre>
+
Length.as_sqlserver = sqlserver_length</syntaxhighlight>
  
 
</div>
 
</div>
  
 
</div>
 
</div>
You can also customize the SQL using the <code>template</code> parameter of <code>as_sql()</code>.
+
您还可以使用 <code>as_sql()</code> <code>template</code> 参数自定义 SQL。
  
We use <code>as_sqlserver()</code> because <code>django.db.connection.vendor</code> returns
+
我们使用 <code>as_sqlserver()</code> 是因为 <code>django.db.connection.vendor</code> 为后端返回 <code>sqlserver</code>
<code>sqlserver</code> for the backend.
 
  
Third-party backends can register their functions in the top level
+
第三方后端可以在后端包的顶级<code>__init__.py</code>文件或从顶级[导入的顶级<code>expressions.py</code>文件(或包)中注册其功能X191X]。
<code>__init__.py</code> file of the backend package or in a top level <code>expressions.py</code>
 
file (or package) that is imported from the top level <code>__init__.py</code>.
 
  
For user projects wishing to patch the backend that they're using, this code
+
对于希望修补他们正在使用的后端的用户项目,此代码应位于 [[../../applications#django.apps.AppConfig|AppConfig.ready()]] 方法中。
should live in an [[../../applications#django.apps.AppConfig|<code>AppConfig.ready()</code>]] method.
 
  
  
第1,591行: 第1,294行:
  
 
</div>
 
</div>
 +
 +
</div>
 +
<div class="clearer">
 +
 +
  
 
</div>
 
</div>
  
[[Category:Django 2.2.x 中文文档]]
+
[[Category:Django 2.2.x 文档]]

2021年10月31日 (日) 04:05的最新版本

查询表达式

查询表达式描述可用作更新、创建、过滤、排序依据、注释或聚合的一部分的值或计算。 有许多内置表达式(记录如下)可用于帮助您编写查询。 表达式可以组合,或在某些情况下嵌套,以形成更复杂的计算。

支持的算术

Django 支持负、加、减、乘、除、模数运算,以及对查询表达式的幂运算符,使用 Python 常量、变量,甚至其他表达式。

2.1 版更改: 添加了对否定的支持。


一些例子

from django.db.models import Count, F, Value
from django.db.models.functions import Length, Upper

# Find companies that have more employees than chairs.
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(), either directly
Company.objects.order_by(Length('name').asc())
Company.objects.order_by(Length('name').desc())
# or using the double underscore lookup syntax.
from django.db.models import CharField
from django.db.models.functions import Length
CharField.register_lookup(Length)
Company.objects.order_by('name__length')

内置表达式

笔记

这些表达式在 django.db.models.expressionsdjango.db.models.aggregates 中定义,但为了方便起见,它们可用并且通常从 django.db.models 导入。


F() 表达式

class F

F() 对象表示模型字段或注释列的值。 它可以引用模型字段值并使用它们执行数据库操作,而实际上不必将它们从数据库中提取到 Python 内存中。

相反,Django 使用 F() 对象生成一个 SQL 表达式,该表达式描述了数据库级别所需的操作。

这通过一个例子最容易理解。 通常,人们可能会这样做:

# Tintin filed a news story!
reporter = Reporters.objects.get(name='Tintin')
reporter.stories_filed += 1
reporter.save()

在这里,我们已经将 reporter.stories_filed 的值从数据库拉入内存并使用熟悉的 Python 运算符对其进行操作,然后将对象保存回数据库。 但我们也可以这样做:

from django.db.models import F

reporter = Reporters.objects.get(name='Tintin')
reporter.stories_filed = F('stories_filed') + 1
reporter.save()

尽管 reporter.stories_filed = F('stories_filed') + 1 看起来像一个普通的 Python 将值分配给实例属性,但实际上它是一个描述数据库操作的 SQL 构造。

当 Django 遇到 F() 的实例时,它会覆盖标准的 Python 操作符来创建一个封装的 SQL 表达式; 在这种情况下,它指示数据库增加由 reporter.stories_filed 表示的数据库字段。

无论 reporter.stories_filed 上的值是什么或曾经是什么,Python 永远不会知道它——它完全由数据库处理。 通过 Django 的 F() 类,Python 所做的一切就是创建 SQL 语法来引用该字段并描述操作。

要访问以这种方式保存的新值,必须重新加载对象:

reporter = Reporters.objects.get(pk=reporter.pk)
# Or, more succinctly:
reporter.refresh_from_db()

除了用于上述单个实例的操作外,F() 还可以用于对象实例的 QuerySets,与 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)

F() 因此可以通过以下方式提供性能优势:

  • 让数据库,而不是 Python 来完成工作
  • 减少某些操作所需的查询次数

使用 F() 避免竞争条件

F() 的另一个有用的好处是让数据库 - 而不是 Python - 更新字段的值避免了 竞争条件

如果两个 Python 线程执行上面第一个示例中的代码,则一个线程可以在另一个线程从数据库中检索字段值后检索、递增和保存该字段的值。 第二个线程保存的值会以原来的值为准; 第一个线程的工作将简单地丢失。

如果数据库负责更新字段,则该过程更加健壮:它只会在 save()update() 时根据数据库中字段的值更新字段] 被执行,而不是基于它在检索实例时的值。


F() 分配在 Model.save() 之后仍然存在

F() 分配给模型字段的对象在保存模型实例后仍然存在,并将应用于每个 save()。 例如:

reporter = Reporters.objects.get(name='Tintin')
reporter.stories_filed = F('stories_filed') + 1
reporter.save()

reporter.name = 'Tintin Jr.'
reporter.save()

在这种情况下,stories_filed 将更新两次。 如果最初为 1,则最终值为 3。 可以通过在保存模型对象后重新加载它来避免这种持久性,例如,通过使用 refresh_from_db()


在过滤器中使用 F()

F()QuerySet 过滤器中也非常有用,它们可以根据字段值而不是 Python 值根据条件过滤一组对象。

这在 中使用查询 中的 F() 表达式进行了记录。


将 F() 与注释一起使用

F() 可用于通过将不同字段与算术组合来在模型上创建动态字段:

company = Company.objects.annotate(
    chairs_needed=F('num_employees') - 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('manufacturer'))[0]
>> car.manufacturer
<Manufacturer: Toyota>
>> car.built_by
3

使用 F() 对空值进行排序

使用 F()nulls_firstnulls_last 关键字参数到 Expression.asc()desc() 来控制排序字段的空值。 默认情况下,排序取决于您的数据库。

例如,要在联系过的公司之后对未联系过的公司进行排序(last_contacted 为空):

from django.db.models import F
Company.object.order_by(F('last_contacted').desc(nulls_last=True))

Func() 表达式

Func() 表达式是所有涉及数据库函数(如 COALESCELOWER)或聚合(如 SUM)的基本类型。 它们可以直接使用:

from django.db.models import F, Func

queryset.annotate(field_lower=Func(F('field'), function='LOWER'))

或者它们可用于构建数据库函数库:

class Lower(Func):
    function = 'LOWER'

queryset.annotate(field_lower=Lower('field'))

但是这两种情况都会产生一个查询集,其中每个模型都用一个额外的属性 field_lower 进行注释,大致来自以下 SQL:

SELECT
    ...
    LOWER("db_table"."field") as "field_lower"

有关内置数据库函数的列表,请参阅 数据库函数

Func API 如下:

class Func(*expressions, **extra)
function

描述将生成的函数的类属性。 具体来说,function 将作为 模板 内的 function 占位符进行插值。 默认为 None

template

作为格式字符串的类属性,用于描述为此函数生成的 SQL。 默认为 '%(function)s(%(expressions)s)'

如果您正在构建类似 strftime('%W', 'date') 的 SQL 并且需要在查询中使用文字 % 字符,请将其 (%%%%) 在 template 属性中乘以四倍,因为字符串插值两次:一次是在 as_sql() 中的模板插值期间,一次是在使用数据库游标中的查询参数的 SQL 插值中。

arg_joiner

一个类属性,表示用于将 expressions 列表连接在一起的字符。 默认为 ', '

arity

一个类属性,表示函数接受的参数数量。 如果设置了此属性并且使用不同数量的表达式调用函数,则会引发 TypeError。 默认为 None

as_sql(compiler, connection, function=None, template=None, arg_joiner=None, **extra_context)

为数据库函数生成 SQL。

as_vendor() 方法应使用 functiontemplatearg_joiner 和任何其他 **extra_context 参数来根据需要自定义 SQL。 例如:

django/db/models/functions.py

class ConcatPair(Func):
    ...
    function = 'CONCAT'
    ...

    def as_mysql(self, compiler, connection, **extra_context):
        return super().as_sql(
            compiler, connection,
            function='CONCAT_WS',
            template="%(function)s('', %(expressions)s)",
            **extra_context
        )

为了避免 SQL 注入漏洞,extra_context 不得包含不受信任的用户输入 ,因为这些值被插入到 SQL 字符串中,而不是作为查询参数传递,数据库驱动程序会在其中对它们进行转义。

*expressions 参数是该函数将应用于的位置表达式列表。 表达式将转换为字符串,与 arg_joiner 连接在一起,然后作为 expressions 占位符插入到 template 中。

位置参数可以是表达式或 Python 值。 字符串被假定为列引用并将被包装在 F() 表达式中,而其他值将被包装在 Value() 表达式中。

**extra kwargs 是 key=value 对,可以插入到 template 属性中。 为避免 SQL 注入漏洞,extra 不得包含不受信任的用户输入 ,因为这些值被插入到 SQL 字符串中,而不是作为查询参数传递,数据库驱动程序会在其中对它们进行转义。

functiontemplatearg_joiner 关键字可用于替换同名的属性,而无需定义您自己的类。 output_field 可用于定义预期的返回类型。


Aggregate() 表达式

聚合表达式是 Func() 表达式 的一个特例,它通知查询需要一个 GROUP BY 子句。 所有 聚合函数 ,如 Sum()Count(),都继承自 Aggregate()

由于 Aggregates 是表达式和包装表达式,您可以表示一些复杂的计算:

from django.db.models import Count

Company.objects.annotate(
    managers_required=(Count('num_employees') / 4) + Count('num_managers'))

Aggregate API 如下:

class Aggregate(*expressions, output_field=None, distinct=False, filter=None, **extra)
template

一个类属性,作为格式字符串,描述为此聚合生成的 SQL。 默认为 '%(function)s(%(distinct)s%(expressions)s)'

function

描述将生成的聚合函数的类属性。 具体来说,function 将作为 模板 内的 function 占位符进行插值。 默认为 None

window_compatible

默认为 True,因为大多数聚合函数都可以用作 Window 中的源表达式。

allow_distinct

2.2 版中的新功能。

确定此聚合函数是否允许传递 distinct 关键字参数的类属性。 如果设置为 False(默认),如果通过 distinct=True,则会引发 TypeError

expressions 位置参数可以包括表达式或模型字段的名称。 它们将被转换为字符串并用作 template 中的 expressions 占位符。

output_field 参数需要一个模型字段实例,如 IntegerField()BooleanField(),Django 将在从数据库中检索值后将其加载到其中。 通常在实例化模型字段时不需要参数,因为任何与数据验证相关的参数(max_lengthmax_digits 等)都不会在表达式的输出值上强制执行。

注意 output_field 仅在 Django 无法确定结果应该是什么字段类型时才需要。 混合字段类型的复杂表达式应定义所需的 output_field。 例如,将一个 IntegerField() 和一个 FloatField() 加在一起应该可能定义了 output_field=FloatField()

distinct 参数确定是否应为 expressions 的每个不同值(或多个 expressions 的值集)调用聚合函数。 该参数仅在 allow_distinct 设置为 True 的聚合上受支持。

filter 参数采用 Q 对象 ,用于过滤聚合的行。 有关示例用法,请参阅 条件聚合注释过滤

**extra kwargs 是 key=value 对,可以插入到 template 属性中。

2.2 新功能: 添加了 allow_distinct 属性和 distinct 参数。


创建你自己的聚合函数

创建自己的聚合非常容易。 至少,您需要定义 function,但您也可以完全自定义生成的 SQL。 下面是一个简短的例子:

from django.db.models import Aggregate

class Sum(Aggregate):
    # Supports SUM(ALL field).
    function = 'SUM'
    template = '%(function)s(%(all_values)s%(expressions)s)'
    allow_distinct = False

    def __init__(self, expression, all_values=False, **extra):
        super().__init__(
            expression,
            all_values='ALL ' if all_values else '',
            **extra
        )

Value() 表达式

class Value(value, output_field=None)

Value() 对象表示表达式的最小可能组件:一个简单的值。 当您需要在表达式中表示整数、布尔值或字符串的值时,您可以将该值包装在 Value() 中。

您很少需要直接使用 Value()。 当您编写表达式 F('field') + 1 时,Django 将 1 隐式包装在 Value() 中,从而允许在更复杂的表达式中使用简单的值。 当您想将字符串传递给表达式时,您需要使用 Value()。 大多数表达式将字符串参数解释为字段的名称,例如 Lower('name')

value 参数描述要包含在表达式中的值,例如 1TrueNone。 Django 知道如何将这些 Python 值转换为它们对应的数据库类型。

output_field 参数应该是一个模型字段实例,如 IntegerField()BooleanField(),Django 将在从数据库中检索值后将其加载到其中。 通常在实例化模型字段时不需要参数,因为任何与数据验证相关的参数(max_lengthmax_digits 等)都不会在表达式的输出值上强制执行。


ExpressionWrapper() 表达式

class ExpressionWrapper(expression, output_field)

ExpressionWrapper 只是围绕另一个表达式,并提供对其他表达式可能不可用的属性的访问,例如 output_fieldExpressionWrapper 在对具有不同类型的 F() 表达式使用算术时是必需的,如 使用带注释的 F() 中所述。


条件表达式

条件表达式允许您在查询中使用 if ... elif ... else 逻辑。 Django 本身支持 SQL CASE 表达式。 有关更多详细信息,请参阅 条件表达式


Subquery() 表达式

class Subquery(queryset, output_field=None)

您可以使用 Subquery 表达式向 QuerySet 添加显式子查询。

例如,要使用该帖子的最新评论的作者的电子邮件地址来注释每个帖子:

>>> from django.db.models import OuterRef, Subquery
>>> newest = Comment.objects.filter(post=OuterRef('pk')).order_by('-created_at')
>>> Post.objects.annotate(newest_commenter_email=Subquery(newest.values('email')[:1]))

在 PostgreSQL 上,SQL 看起来像:

SELECT "post"."id", (
    SELECT U0."email"
    FROM "comment" U0
    WHERE U0."post_id" = ("post"."id")
    ORDER BY U0."created_at" DESC LIMIT 1
) AS "newest_commenter_email" FROM "post"

笔记

本节中的示例旨在展示如何强制 Django 执行子查询。 在某些情况下,可以编写一个等效的查询集来更清晰或更高效地执行相同的任务。


从外部查询集中引用列

class OuterRef(field)

Subquery 中的查询集需要引用外部查询中的字段时,请使用 OuterRef。 它的作用类似于 F 表达式,只是在解析外部查询集之前不会检查它是否引用了有效字段。

OuterRef 的实例可以与 Subquery 的嵌套实例结合使用,以引用不是直接父级的包含查询集。 例如,这个查询集需要在一对嵌套的 Subquery 实例中才能正确解析:

>>> Book.objects.filter(author=OuterRef(OuterRef('pk')))

将子查询限制为单列

有时必须从 Subquery 返回单个列,例如,使用 Subquery 作为 __in 查找的目标。 要返回最后一天内发布的帖子的所有评论:

>>> from datetime import timedelta
>>> from django.utils import timezone
>>> one_day_ago = timezone.now() - timedelta(days=1)
>>> posts = Post.objects.filter(published_at__gte=one_day_ago)
>>> Comment.objects.filter(post__in=Subquery(posts.values('pk')))

在这种情况下,子查询必须使用 values() 仅返回单个列:帖子的主键。


将子查询限制为单行

为了防止子查询返回多行,使用了查询集的切片 ([:1]):

>>> subquery = Subquery(newest.values('email')[:1])
>>> Post.objects.annotate(newest_commenter_email=subquery)

在这种情况下,子查询必须只返回单列 和单行 :最近创建的评论的电子邮件地址。

(使用 get() 而不是切片会失败,因为在 Subquery 中使用查询集之前,无法解析 OuterRef。)


Exists() 子查询

class Exists(queryset)

Exists 是使用 SQL EXISTS 语句的 Subquery 子类。 在许多情况下,它会比子查询执行得更好,因为当找到第一个匹配行时,数据库能够停止对子查询的评估。

例如,要注释每个帖子是否有最后一天的评论:

>>> from django.db.models import Exists, OuterRef
>>> from datetime import timedelta
>>> from django.utils import timezone
>>> one_day_ago = timezone.now() - timedelta(days=1)
>>> recent_comments = Comment.objects.filter(
...     post=OuterRef('pk'),
...     created_at__gte=one_day_ago,
... )
>>> Post.objects.annotate(recent_comment=Exists(recent_comments))

在 PostgreSQL 上,SQL 看起来像:

SELECT "post"."id", "post"."published_at", EXISTS(
    SELECT U0."id", U0."post_id", U0."email", U0."created_at"
    FROM "comment" U0
    WHERE (
        U0."created_at" >= YYYY-MM-DD HH:MM:SS AND
        U0."post_id" = ("post"."id")
    )
) AS "recent_comment" FROM "post"

没有必要强制 Exists 引用单个列,因为这些列被丢弃并返回一个布尔结果。 同样,由于排序在 SQL EXISTS 子查询中并不重要,只会降低性能,因此它会被自动删除。

您可以使用 NOT EXISTS~Exists() 进行查询。


过滤 Subquery 表达式

无法直接使用 SubqueryExists 进行过滤,例如:

>>> Post.objects.filter(Exists(recent_comments))
...
TypeError: 'Exists' object is not iterable

您必须首先注释查询集,然后根据该注释过滤子查询表达式:

>>> Post.objects.annotate(
...     recent_comment=Exists(recent_comments),
... ).filter(recent_comment=True)

在 Subquery 表达式中使用聚合

聚合可以在 Subquery 中使用,但它们需要 filter()values()annotate() 的特定组合以获得正确的子查询分组。

假设两个模型都有一个 length 字段,以查找帖子长度大于所有组合评论总长度的帖子:

>>> from django.db.models import OuterRef, Subquery, Sum
>>> comments = Comment.objects.filter(post=OuterRef('pk')).order_by().values('post')
>>> total_comments = comments.annotate(total=Sum('length')).values('total')
>>> Post.objects.filter(length__gt=Subquery(total_comments))

初始的 filter(...) 将子查询限制为相关参数。 order_by() 删除 Comment 模型上的默认 排序 (如果有)。 values('post') 汇总了 Post 的评论。 最后,annotate(...) 执行聚合。 应用这些查询集方法的顺序很重要。 在这种情况下,由于子查询必须限制为单个列,因此需要 values('total')

这是在 Subquery 中执行聚合的唯一方法,因为使用 aggregate() 尝试评估查询集(如果有 OuterRef,这不会可以解决)。


原始 SQL 表达式

class RawSQL(sql, params, output_field=None)

有时数据库表达式不能轻易表达复杂的 WHERE 子句。 在这些边缘情况下,请使用 RawSQL 表达式。 例如:

>>> from django.db.models.expressions import RawSQL
>>> queryset.annotate(val=RawSQL("select col from sometable where othercol = %s", (someparam,)))

这些额外的查找可能无法移植到不同的数据库引擎(因为您正在明确编写 SQL 代码)并且违反 DRY 原则,因此您应该尽可能避免它们。

警告

为了防止 SQL 注入攻击 ,您必须转义用户可以使用 params 控制的任何参数。 params 是强制您承认您没有使用用户提供的数据插入 SQL 的必需参数。

您也不得在 SQL 字符串中引用占位符。 由于 %s 周围的引号,此示例容易受到 SQL 注入攻击:

RawSQL("select col from sometable where othercol = '%s'")  # unsafe!

您可以阅读有关 Django SQL 注入保护 工作原理的更多信息。


窗口函数

窗口函数提供了一种在分区上应用函数的方法。 与为 group by 定义的每个集合计算最终结果的普通聚合函数不同,窗口函数对 和分区进行操作,并计算每一行的结果。

您可以在同一个查询中指定多个窗口,这在 Django ORM 中相当于在 QuerySet.annotate() 调用中包含多个表达式。 ORM 不使用命名窗口,而是它们是选定列的一部分。

class Window(expression, partition_by=None, order_by=None, frame=None, output_field=None)
filterable

默认为 False。 SQL 标准不允许在 WHERE 子句中引用窗口函数,并且 Django 在构造一个 QuerySet 时会引发异常。

template

默认为 %(expression)s OVER (%(window)s)'。 如果仅提供 expression 参数,则 window 子句将为空白。

Window 类是 OVER 子句的主要表达式。

expression 参数是 窗口函数聚合函数 或与窗口子句兼容的表达式。

partition_by 参数是控制行分区的表达式列表(列名应包含在 F 对象中)。 分区缩小了用于计算结果集的行。

output_field 被指定为参数或表达式。

order_by 参数接受一系列表达式,您可以在这些表达式上调用 asc()desc()。 排序控制应用表达式的顺序。 例如,如果对分区中的行求和,第一个结果就是第一行的值,第二个结果是第一行和第二行的总和。

frame 参数指定应在计算中使用的其他行。 有关详细信息,请参阅

例如,要使用同一工作室、同一类型和发行年份的电影的平均评分来注释每部电影:

>>> from django.db.models import Avg, F, Window
>>> from django.db.models.functions import ExtractYear
>>> Movie.objects.annotate(
>>>     avg_rating=Window(
>>>         expression=Avg('rating'),
>>>         partition_by=[F('studio'), F('genre')],
>>>         order_by=ExtractYear('released').asc(),
>>>     ),
>>> )

这可以让你检查一部电影的评分是好是坏,与它的同行相比。

您可能希望在同一个窗口(即同一个分区和框架)上应用多个表达式。 例如,您可以修改前面的示例,通过在同一查询中使用三个窗口函数,还包括每个电影组(相同的工作室、流派和发行年份)中的最佳和最差评级。 将上一个示例中的分区和排序提取到字典中以减少重复:

>>> from django.db.models import Avg, F, Max, Min, Window
>>> from django.db.models.functions import ExtractYear
>>> window = {
>>>    'partition_by': [F('studio'), F('genre')],
>>>    'order_by': ExtractYear('released').asc(),
>>> }
>>> Movie.objects.annotate(
>>>     avg_rating=Window(
>>>         expression=Avg('rating'), **window,
>>>     ),
>>>     best=Window(
>>>         expression=Max('rating'), **window,
>>>     ),
>>>     worst=Window(
>>>         expression=Min('rating'), **window,
>>>     ),
>>> )

在 Django 的内置数据库后端中,MySQL 8.0.2+、PostgreSQL 和 Oracle 支持窗口表达式。 对不同窗口表达式功能的支持因数据库而异。 例如,可能不支持 asc()desc() 中的选项。 根据需要查阅您的数据库的文档。

对于一个窗口帧,你可以选择基于范围的行序列或普通的行序列。

class ValueRange(start=None, end=None)
frame_type

此属性设置为 'RANGE'

PostgreSQL 对 ValueRange 的支持有限,只支持使用标准的起点和终点,例如 CURRENT ROWUNBOUNDED FOLLOWING

class RowRange(start=None, end=None)
;; frame_type
此属性设置为 'ROWS'

这两个类都返回带有模板的 SQL:

%(frame_type)s BETWEEN %(start)s AND %(end)s

框架缩小了用于计算结果的行。 它们从某个起点转移到某个指定的终点。 框架可以使用和不使用分区,但指定窗口的顺序以确保确定性结果通常是个好主意。 在框架中,框架中的对等点是具有等效值的行,或者如果不存在排序子句,则是所有行。

帧的默认起点是 UNBOUNDED PRECEDING,它是分区的第一行。 终点始终明确包含在 ORM 生成的 SQL 中,默认情况下为 UNBOUNDED FOLLOWING。 默认框架包括从分区到集合中最后一行的所有行。

startend 参数的可接受值为 None、整数或零。 start 的负整数产生 N preceding,而 None 产生 UNBOUNDED PRECEDING。 对于 startend,零将返回 CURRENT ROWend 接受正整数。

CURRENT ROW 包含的内容有所不同。 在 ROWS 模式下指定时,帧以当前行开始或结束。 当在 RANGE 模式下指定时,帧根据排序条款在第一个或最后一个对等点开始或结束。 因此,RANGE CURRENT ROW 为具有由排序指定的相同值的行计算表达式。 因为模板同时包含 startend 点,这可以表示为:

ValueRange(start=0, end=0)

如果一部电影的“同行”被描述为同一年同一类型的同一工作室发行的电影,这个 RowRange 示例用电影的两个前两个同行和两个后续同行的平均评分来注释每部电影:

>>> from django.db.models import Avg, F, RowRange, Window
>>> from django.db.models.functions import ExtractYear
>>> Movie.objects.annotate(
>>>     avg_rating=Window(
>>>         expression=Avg('rating'),
>>>         partition_by=[F('studio'), F('genre')],
>>>         order_by=ExtractYear('released').asc(),
>>>         frame=RowRange(start=-2, end=2),
>>>     ),
>>> )

如果数据库支持,您可以根据分区中表达式的值指定起点和终点。 如果 Movie 模型的 released 字段存储每部电影的发行月份,则此 ValueRange 示例使用在前 12 个月之间发行的电影同行的平均评分来注释每部电影每部电影后十二个月。

>>> from django.db.models import Avg, ExpressionList, F, ValueRange, Window
>>> Movie.objects.annotate(
>>>     avg_rating=Window(
>>>         expression=Avg('rating'),
>>>         partition_by=[F('studio'), F('genre')],
>>>         order_by=F('released').asc(),
>>>         frame=ValueRange(start=-12, end=12),
>>>     ),
>>> )

技术信息

您将在下面找到可能对库作者有用的技术实现细节。 下面的技术 API 和示例将有助于创建可以扩展 Django 提供的内置功能的通用查询表达式。

表达式 API

查询表达式实现了 查询表达式 API,但也公开了下面列出的许多额外方法和属性。 所有查询表达式都必须从 Expression() 或相关子类继承。

当一个查询表达式包装另一个表达式时,它负责在被包装的表达式上调用相应的方法。

class Expression
contains_aggregate

告诉 Django 这个表达式包含一个聚合并且需要将 GROUP BY 子句添加到查询中。

contains_over_clause

告诉 Django 这个表达式包含一个 Window 表达式。 例如,它用于在修改数据的查询中禁止窗口函数表达式。

filterable

告诉 Django 这个表达式可以在 QuerySet.filter() 中引用。 默认为 True

window_compatible

告诉 Django 这个表达式可以用作 Window 中的源表达式。 默认为 False

resolve_expression(query=None, allow_joins=True, reuse=None, summarize=False, for_save=False)

提供在将表达式添加到查询之前对其进行任何预处理或验证的机会。 resolve_expression() 也必须在任何嵌套表达式上调用。 selfcopy() 应与任何必要的转换一起返回。

query 是后端查询实现。

allow_joins 是一个布尔值,允许或拒绝在查询中使用连接。

reuse 是一组用于多连接场景的可重用连接。

summarize 是一个布尔值,当 True 表示正在计算的查询是终端聚合查询时。

for_save 是一个布尔值,当 True 时,表示正在执行的查询正在执行创建或更新。

get_source_expressions()

返回内部表达式的有序列表。 例如:

>>> Sum(F('foo')).get_source_expressions()
[F('foo')]
set_source_expressions(expressions)

获取表达式列表并存储它们,以便 get_source_expressions() 可以返回它们。

relabeled_clone(change_map)

返回 self 的克隆(副本),并重新标记任何列别名。 创建子查询时,列别名会被重命名。 relabeled_clone() 也应该在任何嵌套表达式上调用并分配给克隆。

change_map 是一个将旧别名映射到新别名的字典。

例子:

def relabeled_clone(self, change_map):
    clone = copy.copy(self)
    clone.expression = self.expression.relabeled_clone(change_map)
    return clone
convert_value(value, expression, connection)

一个钩子,允许表达式将 value 强制转换为更合适的类型。

get_group_by_cols()

负责通过此表达式返回列引用列表。 get_group_by_cols() 应该在任何嵌套表达式上调用。 F() 对象,特别是,持有对列的引用。

asc(nulls_first=False, nulls_last=False)

返回准备按升序排序的表达式。

nulls_firstnulls_last 定义空值的排序方式。 请参阅 使用 F() 对空值进行排序 以获取示例用法。

desc(nulls_first=False, nulls_last=False)

返回准备好降序排序的表达式。

nulls_firstnulls_last 定义空值的排序方式。 请参阅 使用 F() 对空值进行排序 以获取示例用法。

reverse_ordering()

返回 self 以及在 order_by 调用中反转排序顺序所需的任何修改。 例如,实现 NULLS LAST 的表达式会将其值更改为 NULLS FIRST。 只有实现排序顺序的表达式(如 OrderBy)才需要修改。 当在查询集上调用 reverse() 时调用此方法。


编写自己的查询表达式

您可以编写自己的查询表达式类,这些类使用并可以与其他查询表达式集成。 让我们通过编写 COALESCE SQL 函数的实现来逐步完成一个示例,而不使用内置的 Func() 表达式

COALESCE SQL 函数被定义为获取列或值的列表。 它将返回不是 NULL 的第一列或值。

我们将首先定义用于 SQL 生成的模板和一个 __init__() 方法来设置一些属性:

import copy
from django.db.models import Expression

class Coalesce(Expression):
    template = 'COALESCE( %(expressions)s )'

    def __init__(self, expressions, output_field):
      super().__init__(output_field=output_field)
      if len(expressions) < 2:
          raise ValueError('expressions must have at least 2 elements')
      for expression in expressions:
          if not hasattr(expression, 'resolve_expression'):
              raise TypeError('%r is not an Expression' % expression)
      self.expressions = expressions

我们对参数进行了一些基本验证,包括要求至少有 2 个列或值,并确保它们是表达式。 我们在这里要求 output_field 以便 Django 知道将最终结果分配给什么样的模型字段。

现在我们实现预处理和验证。 由于此时我们没有任何自己的验证,我们只委托给嵌套表达式:

def resolve_expression(self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False):
    c = self.copy()
    c.is_summary = summarize
    for pos, expression in enumerate(self.expressions):
        c.expressions[pos] = expression.resolve_expression(query, allow_joins, reuse, summarize, for_save)
    return c

接下来,我们编写负责生成 SQL 的方法:

def as_sql(self, compiler, connection, template=None):
    sql_expressions, sql_params = [], []
    for expression in self.expressions:
        sql, params = compiler.compile(expression)
        sql_expressions.append(sql)
        sql_params.extend(params)
    template = template or self.template
    data = {'expressions': ','.join(sql_expressions)}
    return template % data, params

def as_oracle(self, compiler, connection):
    """
    Example of vendor specific handling (Oracle in this case).
    Let's make the function name lowercase.
    """
    return self.as_sql(compiler, connection, template='coalesce( %(expressions)s )')

as_sql() 方法可以支持自定义关键字参数,允许 as_vendorname() 方法覆盖用于生成 SQL 字符串的数据。 使用 as_sql() 关键字参数进行自定义比在 as_vendorname() 方法中改变 self 更可取,因为后者在不同的数据库后端上运行时会导致错误。 如果您的类依赖类属性来定义数据,请考虑在您的 as_sql() 方法中允许覆盖。

我们使用 compiler.compile() 方法为每个 expressions 生成 SQL,并将结果用逗号连接在一起。 然后用我们的数据填充模板,并返回 SQL 和参数。

我们还定义了一个特定于 Oracle 后端的自定义实现。 如果使用 Oracle 后端,将调用 as_oracle() 函数而不是 as_sql()

最后,我们实现了其余的方法,使我们的查询表达式可以与其他查询表达式配合使用:

def get_source_expressions(self):
    return self.expressions

def set_source_expressions(self, expressions):
    self.expressions = expressions

让我们看看它是如何工作的:

>>> from django.db.models import F, Value, CharField
>>> qs = Company.objects.annotate(
...    tagline=Coalesce([
...        F('motto'),
...        F('ticker_name'),
...        F('description'),
...        Value('No Tagline')
...        ], output_field=CharField()))
>>> for c in qs:
...     print("%s: %s" % (c.name, c.tagline))
...
Google: Do No Evil
Apple: AAPL
Yahoo: Internet Company
Django Software Foundation: No Tagline

避免 SQL 注入

由于 __init__() (**extra) 和 as_sql() (**extra_context) 的 Func 的关键字参数被插入到 SQL 字符串中而不是作为查询参数传递(数据库驱动程序将在其中转义它们),它们不能包含不受信任的用户输入。

例如,如果 substring 是用户提供的,则此函数容易受到 SQL 注入:

from django.db.models import Func

class Position(Func):
    function = 'POSITION'
    template = "%(function)s('%(substring)s' in %(expressions)s)"

    def __init__(self, expression, substring):
        # substring=substring is a SQL injection vulnerability!
        super().__init__(expression, substring=substring)

此函数生成不带任何参数的 SQL 字符串。 由于 substring 作为关键字参数传递给 super().__init__(),它在查询发送到数据库之前被插入到 SQL 字符串中。

这是一个更正的重写:

class Position(Func):
    function = 'POSITION'
    arg_joiner = ' IN '

    def __init__(self, expression, substring):
        super().__init__(substring, expression)

使用 substring 代替作为位置参数传递,它将作为数据库查询中的参数传递。


在第三方数据库后端增加支持

如果您使用的数据库后端对某个函数使用不同的 SQL 语法,您可以通过将新方法添加到函数的类上来添加对它的支持。

假设我们正在为 Microsoft 的 SQL Server 编写后端,它使用 SQL LEN 而不是 Length 函数的 LENGTH。 我们将在 Length 类上添加一个名为 as_sqlserver() 的新方法:

from django.db.models.functions import Length

def sqlserver_length(self, compiler, connection):
    return self.as_sql(compiler, connection, function='LEN')

Length.as_sqlserver = sqlserver_length

您还可以使用 as_sql()template 参数自定义 SQL。

我们使用 as_sqlserver() 是因为 django.db.connection.vendor 为后端返回 sqlserver

第三方后端可以在后端包的顶级__init__.py文件或从顶级[导入的顶级expressions.py文件(或包)中注册其功能X191X]。

对于希望修补他们正在使用的后端的用户项目,此代码应位于 AppConfig.ready() 方法中。