附录 B 数据模型定义参考

优质
小牛编辑
128浏览
2023-12-01

第五章解释了定义模式的基本方式,并且我们在整本书都用到了它们。然而,有相当数量的模型选项我们没有提到过。这个附录解释了每个可能的模型定义选项。

注意,虽然这些 API 被认作是非常稳定的,不过 Django 的开发者们会一贯地保持将新的快捷和方便加入到模型定义中。经常检查最新的在线文档是个好主意: http://www.djangoproject.com/documentation/0.96/model-api/

字段

一个模型最重要也是唯一必需的部分,是它定义的数据库字段。字段名称限制

Django 对模型的字段名做了两个限制

一个字段名不能是一个 Python 保留字,因为那样会导致一个 Python 语法错误,例如: class Example(models.Model):

pass = models.IntegerField() # 'pass' is a reserved word!

一个字段名不能包含连续的一个以上的下划线,因为那是 Django 查询语句的语法。例如: class Example(models.Model):

foo__bar = models.IntegerField() # 'foo__bar' has two underscores!

不过这些限制可以被绕过,因为字段名不一定要和数据库列名称完全相同。参见下面的

db_column 。

SQL 保留字,像 join 、 where 或 select , 可以 用在模型字段名中,因为 Django 在每个 SQL 查询中,会对所有的数据库表名称和列名称进行转义。它会根据不同的数据库引擎的引用语法来进行相应的转义。

你的模型的每个字段应该是一个适当的 Field 类的实例,Django 使用这个字段类的类型去确定如下内容:

  • 数据库列类型(如 INTEGER 、 VARCHAR )。

  • 在 Django 的 admin 界面中使用的部件,如果你想要指定的话。(例如: <input

    type="text"> 、 <select> )。

  • 用于 Django 的 admin 界面的基本的合法性验证。

下面是一个完整的按照字母排序的字段列表。注意关系字段( ForeignKey 等)会在下一节里说明。

AutoField

指一个能够根据可用 ID 自增的 IntegerField 。通常你不用直接使用它,如果你没有指定主键的话,系统会自动在你的模型中加入这样的主键。

BooleanField

一个真/假(true/false)字段。

CharField

一个字符串字段,适用于中小长度的字符串。对于长段的文字,请使用 TextField 。

CharField 有一个额外的必需参数: maxlength ,它是字段的最大长度(字符数)。这个最大长度在数据库层面和 Django 验证中是被强制要求的。

CommaSeparatedIntegerField

一个用逗号分隔开的整数字段。和 CharField 中一样, maxlength 参数是必需的。

DateField

日期字段。 DateField 有一些额外的可选参数,如表 B-1 所示。

表 B-1. 额外的 DateField 选项

Argument

Description

auto_now

每次对象保存时,自动设置为当前日期。一般用来产生最后一次修改时间。

注意:使用此选项的字段的值总是在保存时被设置为保存时的日期,这是无法 改变的。

auto_now_add

当对象第一次产生时字段设置为当前日期。一般用来产生对象的建立时间。

注意:使用此选项的字段值总是在对象建立时被设置为建立时的日期,这是无 法改变的。

DateTimeField

时间日期字段。接受跟 DateField 一样的额外选项。

EmailField

一个能检查值是否是有效的电子邮件地址的 CharField 。不接受 maxlength 参数,它的

maxlength 被自动设置为 75。

FileField

一个文件上传字段。它有一个 必需的 参数,如表 B-3 所示。

表 B-2. 额外的 FileField 选项

参数

描述

upload_to

一 个 本 地 的 文 件 系 统 路 径 , 被 附 加 到 你 的 MEDIA_ROOT 设 置 后 面 , 这 决 定 了

get_<fieldname>_url() 辅助函数的输出

这个路径可以包含 strftime 格式串(参见 http://www.djangoproject.com/r/python/strftime/ ),文件上传时就会用当时的具体日期/时间替换(这样给定的目录就不会被上传的文件塞满了)。

在模型中使用 FileField 或者 ImageField 时,要有以下的步骤:

  1. 在 settings 文件中你需要定义 MEDIA_ROOT ,它就是你要保存上传文件的目录的全路径。(出于性能考虑,这些文件不会保存到数据库中。)还要定义 MEDIA_URL ,刚才那个目录的对外 URL。你要确保网络服务器使用的用户对这个目录是可写入的。

  2. 在模型中添加 FileField 或者 ImageField ,务必要定义 upload_to 选项,这样

    Django 才知道把上传的文件写到 MEDIA_ROOT 的哪个子目录中。

  3. 保存到数据库中的只有文件(相对于 MEDIA_ROOT )的路径。你很可能会使用 Django提供的 get_<fieldname>_url 函数。例如,如果你的 ImageField 叫做 mug_shot 的话,你在模板中使用 {{ object.get_mug_shot_url }} 就会得到图片的绝对 URL 了。

例如,你的 MEDIA_ROOT 设置为 '/home/media' , upload_to 设置为 'photos/%Y/%m/%d' 。其中 '%Y/%m/%d' 部分是日期格式化串: '%Y' 为 4 位的年份, '%m' 是两位月份, '%d' 是两位的日期。如果你在 2007 年 1 月 15 日上传文件,这个文件就会被保存在

/home/media/photos/2007/01/15 目录下。

如果你想得到上传文件在磁盘上的文件名,或者指向该文件的 URL,或者文件大小,你可以 分别使用这些方法: get_FIELD_filename() 、 get_FIELD_url() 和 get_FIELD_size() 。附录 C 中有这些方法的详细解释。

备注

处理上传的文件时,为了避免安全漏洞,你应该总是密切注意上传文件的位置,以及文件的类型。 验证所有上传文件 ,确保文件内容是你所期望的。

例如,你未加验证地盲目的让某人上传文件,恰恰又上传到了网页服务器的根目录下的某个目录中,这个人就可以通过上传一个 CGI 或者 PHP 脚本并访问对应链接来执行那个脚本。不要让这种情况发生。

FilePathField

一个拥有若干可选项的字段,选项被限定为文件系统中某个目录下的文件名。它有 3 个特殊的参数,如表 B-4 所示。

表 B-3. FilePathField 的额外选项

参数

描述

path

必需 ;文件系统中一个目录的绝对路径, FilePathField 将从那个目录得到选项列表(比如:

"/home/images" )。

match

可选;一个正则表达式字符串, FilePathField 用它来过滤文件名。注意,这个正则表达式只作用

于基文件名,而不是全路径(例如: "foo.*\.txt^" 会匹配 foo23.txt ,但是不会匹配 bar.txt 或者 foo23.gif )。

recursive

可选; True 或者 False 。默认值为 False 。它指定是否把 path 的所有子目录都包 含进来。

当然,这些参数可以同时使用。

一个潜在的意料之外的东西就是 match 只作用于基文件名,而不是全路径。所以,看看这个例子:

FilePathField(path="/home/images", match="foo.*", recursive=True)

会匹配 /home/images/foo.gif ,但是不会匹配 /home/images/foo/bar.gif ,因为 match只作用于基文件名( foo.gif 和 bar.gif )。

FloatField

一个浮点数,对应 Python 中的 float 实例。它有两个 必需 的参数,如表 B-2 所示。

表 B-4. FloatField 的额外选项

参数

描述

max_digits

数字中允许的最大的数字位数

decimal_places

数字的小数位数

例如,要保存最大值为 999 并且有两位小数的数字,应该这样写:

models.FloatField(..., max_digits=5, decimal_places=2) 要保存最大值为 10 亿并且带 10 个小数位的数字,要这样写: models.FloatField(..., max_digits=19, decimal_places=10)

ImageField

像 FileField 一样,只不过要验证上传的对象是一个有效的图片。它有两个额外的可选参数:

height_field 和 width_field ,如果设置了的话,每当模型实例被保存的时候,这两个值就会被设置成图片的高度和宽度。

FileField 中有一系列的 get_FIELD_* 方法,作为一种补充, ImageField 提供了

get_FIELD_height() 和 get_FIELD_width() 方法。附录 C 中有相关文档。

ImageField 依赖 Python 图片库( http://www.pythonware.com/products/pil/ )。

IntegerField

一个整数。

IPAddressField

一个 IP 地址,以字符串格式表示(例如: "24.124.1.30" )。

NullBooleanField

就像一个 BooleanField ,但它支持 None /Null 。尽量使用这个,而不要使用设置了

null=True 的 BooleanField 。

PhoneNumberField

它是一个 CharField ,并且会检查值是否是一个合法的美式电话格式,如(XXX-XXX-XXXX)。备注

如果你需要表示一个其他国家的电话号码,检查 django.contrib.localflavor 包,看看是否包括对应你的国家的字段定义。

PositiveIntegerField

和 IntegerField 类似,但必须是正值。

PositiveSmallIntegerField

与 PositiveIntegerField 类似,但只允许小于一定值的值。最大值取决于数据库,但因为数据库有一个 2-byte 的小整数字段,最大的小整数正值一般都是 65,535。

SlugField

嵌条是报纸业的术语。 嵌条 就是一段内容的简短标签,这段内容只能包含字母、数字、下划线或连字符。通常用于 URL 中。

像 CharField 一样,你可以指定 maxlength 。如果没有指定 maxlength ,Django 将使用默认值 50。

由于嵌条主要用于数据库查找,所以 SlugField 默认的就有 db_index=True 。

SlugField 接受一个额外的选项: prepopulate_from ,它是一些字段的列表,而这些字段将在对象管理表单中通过 JavaScript 生成嵌条。

models.SlugField(prepopulate_fpom=("pre_name", "name"))

prepopulate_from 不接受 DateTimeField 字段的名字作为参数。

SmallIntegerField

和 IntegerField 类似,但是只允许在一个数据库相关的范围内的数值(通常是-32,768 到

+32,767)。

TextField

一个不限长度的文字字段。

TimeField

时分秒的时间显示。它接受的可指定参数与 DateField 和 DateTimeField 相同。

URLField

用来存储 URL 的字段。如果 verify_exists 选项被设置为 True (默认),给出的 URL 就会被检测是否存在(例如:这个 URL 的确被加载并且没有给出一个 404 响应)。

和其他字符字段一样, URLField 接受 maxlength 参数。如果你没有指定 maxlength ,则使用默认值 200。

USStateField

美国州名称缩写,两个字母。备注

如果你需要表示其他的国家或地区,查看一下 django.contrib.localflavor 包,看看Django是否已经包含了对应你本地的字段。

XMLField

它就是一个 TextField ,只不过要检查值是匹配指定 schema 的合法 XML。它有一个必需参 数: schema_path ,它是验证字段合法性所需的 RELAX NG( http://www.relaxng.org/

schema 的物理路径。

要验证 XML 合法性需要用到 jing ( http://thaiopensource.com/relaxng/jing.html )工具。

通用字段选项

所有的字段类型都可以使用下面的参数。所有的都是可选的。

null

如果设置为 True 的话,Django 将在数据库中存储空值为 NULL 。默认为 False 。

记住,空字符串值保存时总是以空字符串的形式存在,而不是 NULL 。一般只对非字符串字段使用 null=True ,比如整型、布尔型和日期型。对于这两种字段,如果你允许表单中的对应值为空的话,你还需要设定 blank=True ,因为 null 参数只影响数据库存储(参见下面题为 blank 的一节)。

如果没有充分理由的话,应该尽量避免对诸如 CharField 和 TextField 这样字符串字段使用 null 参数。如果对字符串字段指定了 null=True 的话,这意味着空数据有两种可能的值:

NULL 和空字符串。而大多数情况下,空数据没必要对应两种可能的值,所以 Django 中习惯使用空字符串,而不是 NULL 。

blank

如果是 True ,该字段允许留空,默认为 False 。

注意这与 null 不同, null 完全是数据相关的,而 blank 是用来做验证的。如果一个字段设置了 blank=True ,在 Django 的管理界面会允许该字段留空,如果设置了 blank=False ,那么这就是一个必填字段。

choices

一个包含双元素元组的可迭代的对象,用于给字段提供选项。

如果指定了这个选项,Django 管理界面不会使用标准的文本框了,而是取而代之,使用列表选择框限定选择范围。

下面就是一个选项列表: YEAR_IN_SCHOOL_CHOICES = (

('FR', 'Freshman'),

('SO', 'Sophomore'),

('JR', 'Junior'),

('SR', 'Senior'),

('GR', 'Graduate'),

)

每个元组中的第一个元素是实际存储的值,第二个元素是用于显示给用户的选项。选项列表既可以作为模型类的一部分来定义:

class Foo(models.Model): GENDER_CHOICES = (

('M', 'Male'),

('F', 'Female'),

)

gender = models.CharField(maxlength=1, choices=GENDER_CHOICES)也可以定义到模型类的外面:

GENDER_CHOICES = ( ('M', 'Male'),

('F', 'Female'),

)

class Foo(models.Model):

gender = models.CharField(maxlength=1, choices=GENDER_CHOICES)

对于设定了 choices 选项的模型字段,Django 会添加一个方法,来获取字段当前值对应的用户可读文本。详见附录 C。

db_column

当前字段在数据库中对应的列的名字。如果没有指定的话,Django 会使用这个字段的名字。当你要定义一个数据库中存在命名冲突的模型时,这个选项非常有用。

如果你指定的数据库列名称是SQL 的保留字,或者名称中包含Python 变量名不允许的字符(就是连字符),没问题,Django 会悄悄地把列名或者表名用引号引起来。

db_index

如果为 True ,Django 会在创建表格(比如运行 manage.py syncdb )时对这一列创建数据库索引。

default

字段的默认值。

editable

如果为 False ,这个字段在管理界面或表单里将不能编辑。默认为 True 。

help_text

在管理界面表单对象里显示在字段下面的额外帮助文本。即使你没有管理表单这个属性对文档也是有用的。

primary_key

如果为 True ,这个字段就会成为模型的主键。

如果你没有对模型中的任何字段指定 primary_key=True 的话,Django 会自动添加这个字段: id = models.AutoField('ID', primary_key=True)

所以,如果你不想覆盖默认的主键行为的话,你就不必对任何字段设定 primary_key=True 。

primary_key=True 就意味着 blank=False 、 null=False 和 unique=True 。一个对象只能有一个主键。

radio_admin

默认地,对于 ForeignKey 或者拥有 choices 设置的字段,Django 管理界面会使用列表选择框(<select>)。如果 radio_admin 设置为 True 的话,Django 就会使用单选按钮界面。

如果字段不是 ForeignKey 或者没有 choices 设置的话,就不要对字段只用这个选项。

unique

如果是 True ,这个字段的值在整个表中必须是唯一的。

unique_for_date

把它的值设成一个 DataField 或者 DateTimeField 的字段的名称,可以确保字段在这个日期内不会出现重复值,例如:

class Story(models.Model):

pub_date = models.DateTimeField()

slug = models.SlugField(unique_for_date="pub_date")

...

在上面的代码中,Django 不会允许在同一个日期发表两个嵌条相同的故事。和使用

unique_together 不同的是,它只考虑 pub_date 字段的日期,而忽略掉时间差异。

unique_for_month

和 unique_for_date 类似,只是要求字段在指定字段的月份内唯一。

unique_for_year

和 unique_for_date 及 unique_for_month 类似,只是时间范围变成了一年。

verbose_name

除 ForeignKey 、 ManyToManyField 和 OneToOneField 之外的字段都接受一个详细名称作为第一个位置参数。如果详细名称没有给定的话,Django 会把字段的属性名中的下划线转化成空格后的字符串当作详细名称。

下面的例子中,详细名称是 "Person's first name" :

first_name = models.CharField("Person's first name", maxlength=30)下面的例子中,详细名称是 "first name" :

first_name = models.CharField(maxlength=30)

ForeignKey 、 ManyToManyField 和 OneToOneField 要求第一个参数是一个模型类,所以只能使用关键字参数 verbose_name :

poll = models.ForeignKey(Poll, verbose_name="the related poll") sites = models.ManyToManyField(Site, verbose_name="list of sites") place = models.OneToOneField(Place, verbose_name="related place")

这种转换不会把 verbose_name 的首字母大写,Django 会根据需求自动大写首字母。

关系

很明显,关系数据库的强大在于表与表之间的相互关联关系,Django 提供定义了三种最为通用的数库库关系类型:many-to-one(多对一关系),many-to-many(多对多关系)和

one-to-one(一对一关系)

对于一对一关系,在本书出版时正在被重新审阅,因此本章没有涉及这一点,你可以从在线文档中获取最新信息。

多对一关系

用 ForeignKey 来定义多对一的关系。用法和其他的 Field 是一样的,把它放到模型中类的属性定义中就行了。

ForeignKey 需要一个与之相关联的类作为位置参数。

例如,一个 Car 模型中有个 Manufacturer ,就是说一个 Manufacturer 可以生产很多汽车,但是每个 Car 只能有一个 Manufacturer ,可以这样定义:

class Manufacturer(models.Model):

...

class Car(models.Model):

manufacturer = models.ForeignKey(Manufacturer)

...

要建立一个 递归 的关系——就是一个对象和自身有多对一的关系——可以这样写: models.ForeignKey('self') :

class Employee(models.Model):

manager = models.ForeignKey('self')

如果你创建关系时,所需的模型还没有被定义,你可以不使用模型对象本身,而是使用那个模型的名字。

class Car(models.Model):

manufacturer = models.ForeignKey('Manufacturer')

...

class Manufacturer(models.Model):

...

但是,你要记住,只能对在同一个 models.py 文件中的模型使用字符串引用,对于其他应用程序中的模型或者从其他地方导入的模型是不能使用名字对其做引用的。

Django 在数据库中使用的列名称是对应的字段的名称后追加 _id 得到的字符串。再前面的那个例子中, Car 模型对应的数据库表中会有一个名字是 manufacturer_id 的列,(你可以通过指定 db_column 来显式改变这个名字,参见前面的 db_column 一节)但是,如果你不需要写定制的 SQL 语句的话,你永远不要去处理数据库列名,只需要处理你的模型对象中的字段名称。

建议你使用模型的名字的小写形式作为 ForeignKey 字段的名字(上个例子中的 manufacturer ),但这不是必须的,你当然可以任意命名,例如:

class Car(models.Model):

company_that_makes_it = models.ForeignKey(Manufacturer)

# ...

为了定义关系的细节, ForeignKey 字段接受很多额外的参数(参见表 B-5)。所有的参数都是可选的。

表 B-5. ForeignKey 选项

选项

描述

edit_inline

如果不设为 False 的话,它对应的对象就可以在页面上内联编辑,就是说这个对象有自 己独立的管理界面。如果设为 models.TABULAR 或者 models.STACKED 的话,

这个内 联编辑对象分别显示成一个表格或者一些字段的集合。

limit_choices_to

可以限定对象的值的范围的一个参数和值的字典(参见附录 C)。结合

Python 的 datetime 模块的函数可以根据日期来限定对象。例如,下面的代码:

表 B-5. ForeignKey 选项

选项

描述

limit_choices_to = {'pub_date__lte': datetime.now} 把可选对象限定到 pub_date 早于当前时间的对象中。

除字典外,这里也可以是一个可以执行更复杂的查询的 Q 对象(参见附录 C)。

这个选项和 edit_inline 是不兼容的。

max_num_in_admin

对于内联编辑对象,这个是要在管理界面里显示的相关对象的最多个数。 所以,如果披萨最多 只会有 10 种配料, max_num_in_admin=10 会保证用户最多输入 10 种配料。

记住,本项并不保证不会创建 10 种以上的配料,他只是控制管理界面, 而不是在 Python 的 API 层和数据库层做什么限制。

min_num_in_admin

在管理界面中要显示的相关的对象的最少个数。通常,在创建的时候,显示的内联 对象的个数 为 num_in_admin 个,在编辑的时候,在当前的基础上又会多显示

num_extra_on_change 个空对象,但是显示的对象个数不会少于 min_num_in_admin

个。

num_extra_on_change

修改对象时要额外显示的对象数目。

num_in_admin

添加对象时要显示的内联对象的默认个数。

raw_id_admin

为要键入的整数显示一个文本框,而不是一个下拉列表。在关联对象有很 多行时,这个比显示 一个列表选择框更实用。

使用 edit_inline 时,本项无效。

related_name

关联对象反向引用描述符。更多信息参见附录 C。

to_field

关联对象的用于关联的字段,Django 默认使用关联对象的主键。

多对多关系

用 ManyToManyField 来定义多对多的关系。像 ForeignKey 一样, ManyToManyField 需要一个与之相关联的类作为位置参数。

例如,一个 Pizza 可以有多种 Topping 对象——就是说一种 Topping 可以用在多个披萨上面,同时一个 Pizza 可以有多种配料——你可以这样写:

class Topping(models.Model):

...

class Pizza(models.Model):

toppings = models.ManyToManyField(Topping)

...

像 ForeignKey 一样,和自身的关系可以通过字符串 'self' 来定义,而不用模型名。对于那些尚未定义的模型,你也可以通过模型名字来引用。但是,你只能对在同一个 models.py 文件中的模型使用字符串引用,对于其他应用程序中的模型或者从其他地方导入的模型是不能使用名字对其做引用的。

建议你描述想过模型对象集时,用复数名词作为 ManyToManyField 的名字,但这并不是必须的。

Django 会在后台建立一个起桥梁作用的表来描述多对多关系。

对于有多对多关系的两个模型, ManyToManyField 存在于哪个模型中并不重要,但只能存在于一个模型中。

如果你是用管理界面的话, ManyToManyField 实例应该放到要在管理界面编辑的对象里。在前面的例子里,是 toppings 位于 Pizza 中的(而不是 Topping 中有一个名为 pizzas 的 ManyToManyField ),因为这样比一种配料放到多个披萨中更符合人们的思维习惯。在这个例子中,用户可以在 Pizza 的管理界面中选择配料。

为了定义关系细节, ManyToManyField 对象接受几个额外的参数(参见表 B-6),这些参数都是可选的。

表 B-6. ManyToManyField 选项

参数

描述

related_name

关联对象反向引用描述符。更多信息参见附录 C。

filter_interface

在这个对象的管理界面里面,使用简单易用的 JavaScript 过滤界面,而不是使用可用性较

差的 <select multiple> 。它的值应该是 models.HORIZONTAL 或者 models.VERTICAL (就是说界面应该横放还是竖放)。

limit_choices_to

参见 ForeignKey 中对本项的描述。

symmetrical

仅用于模型定义指向自身的 ManyToManyField 的情况。看下面这个模型:

class Person(models.Model):

friends = models.ManyToManyField("self")

当 Django 处理这个模型时,会发现它有一个指向自身的 ManyToManyField , 它因此就不会在 Person 类中添加 person_set 属性。而对于ManyToManyField ,我们会假定这种 关系是对称的,就是说,如果我是你的朋友,你也是我的朋友。

在对 self 的 ManyToMany 关系中,如果你不需要这种对称性,你可以把

symmetrical 的值设为 False 。这样就会强制 Django 给关系的另外一方添加描述符, 从而使这种关系不是对称的。

表 B-6. ManyToManyField 选项

参数

描述

db_table

用来保存多对多数据的表的名字。如果没有提供本项的话,Django 会把两个表的名字连接起来当 做多对多数据表的默认名字。

模型的 Metadata 选项

在模型类中定义一个 class Meta ,然后可以在其中指定本模型特有的 metadata: class Book(models.Model):

title = models.CharField(maxlength=100)

class Meta:

# model metadata options go here

...

Model metadata 是任何非字段的属性,比如排序选项等等

下面的章节列出了所有可能的 Meta 选项,它们都是可选的,连 class Meta 都不是模型必需的。

db_table

模型对应的数据库表的名字。

为了节省时间,Django 通过你定义的模型的类名和所在的应用程序的名称自动得到数据库的表名,它是由模型的应用程序名称——就是你执行 manage.py startapp 命令所指定的应用程序的名称——和模型的类名组成的,它们之间通过下划线进行连接。

例如,假设你有一个应用程序:books(通过执行 manage.py startapp books 命令创建的),又定义了一个模型: class Book ,那么这个模型对应的默认的数据库表名应该为

books_book 。

通过复写 class Meta 中的 db_table 参数可以改变模型映射的数据库表名: class Book(models.Model):

...

class Meta:

db_table = 'things_to_read'

如果没有指定该选项的话,Django 会使用: app_label + '_' + model_class_name 。参见

“表名”一节。(译注:这一节不知何故,并未在本章中出现,英文原文可参见: http://docs.djangoproject.com/en/dev/ref/models/options/#table-names

如果你指定的数据库表名是 SQL 的保留字,或者名称中包含 Python 变量名不允许的字符(就是连字符),没问题,Django 会悄悄地把列名或者表名用引号引起来。

get_latest_by

模型中的一个 DateField 或者 DataTimeField 字段的名字,它指明模型 Manager 的

latest() 方法使用的默认字段。示例如下:

class CustomerOrder(models.Model): order_date = models.DateTimeField()

...

class Meta:

get_latest_by = "order_date"

关于 latest() 方法的更多信息可参考附录 C。

order_with_respect_to

标识这个对象可以根据指定字段排序,这个主要用于相互关联的对象,让他们可以按照和父对象相关的方式排序。例如,如果 Answer 和 Question 对象相关,同一个问题可能对应多个答案,如果答案顺序很重要的话,你应该这样做:

class Answer(models.Model):

question = models.ForeignKey(Question)

# ...

class Meta:

order_with_respect_to = 'question'

ordering

对象默认的排序方法,获取对象列表时会用到。 class Book(models.Model):

title = models.CharField(maxlength=100)

class Meta:

ordering = ['title']

它就是一个字符串的元组或列表。字符串是一个有可选前缀 - 的字段名,这个前缀表示降序排列。没有前缀 - 则表示升序排列。使用字符串 "?" 可进行随机排序。

例如,要以 title 字段做升序排列(也就是 A-Z),要这样写: ordering = ['title']

要以 title 做降序排列(也就是 Z-A),这样写: ordering = ['-title']

要先以 title 做降序排列,再以 author 做升序排列,就这样写: ordering = ['-title', 'author']

注意,无论 ordering 中有多少字段,admin 界面只使用第一个字段。

permissions

创建对象时,需要额外加入权限表的权限。对于设置了 admin 选项的对象,添加、删除和修改的权限在创建对象时会自动创建。下面的例子指定了一个附加的权限: can_deliver_pizzas :

class Employee(models.Model):

...

class Meta:

permissions = (

("can_deliver_pizzas", "Can deliver pizzas"),

)

它是一个形如 (permission_code, human_readable_permission_name) 的元组的列表。有关权限的更多信息参见第 12 章。

unique_together

组合在一起的一些字段的名字,这些字段的组合值必须是唯一的: class Employee(models.Model):

department = models.ForeignKey(Department) extension = models.CharField(maxlength=10)

...

class Meta:

unique_together = [("department", "extension")]

这是一个由一些字段列表组成的列表,每个列表里的字段的组合值必须是唯一的。它用于

Django 管理界面,而且在数据库层是强制要求的(就是说在 CREATE TABLE 语句中会包含一些 UNIQUE 语句)。

verbose_name

对象的友好可读名称(单数形式): class CustomerOrder(models.Model):

order_date = models.DateTimeField()

...

class Meta:

verbose_name = "order"

如果没有给出此选项,那么 Django 将会根据类名来得到一个名称,例如 CamelCase 就会变成 camel case 。

verbose_name_plural

对象复数形式的名字:

class Sphynx(models.Model):

...

class Meta:

verbose_name_plural = "sphynges"

如果此选项没有指定,则 Django 会在 verbose_name 后面加上个 s 来作为此选项的默认值。

管理器

Manager 是提供给 Django 模型的数据库查询接口。Django 程序的每个模型中至少存在一个

Manager 。

Manager 类的工作原理在附录 C 中详细说明了。本节消息讨论可以定制 Manager 行为的模型选项。

管理器名称

Django 默认会给每个模型添加一个叫做 objects 的 Manager 。如果你想把一个字段命名为

objects 的话,或者你不想把 Manager 命名为 objects ,你可以在每个模型里做修改。在 模型里面定一个 models.Manager() 类型的类属性,就可以修改这个类的 Manager 的名字了,例如:

from django.db import models class Person(models.Model):

...

people = models.Manager()

使用这个例子中的模型时,调用 Person.objects 会引发 AttributeError 异常(因为

Person 没有 objects 属性),但是调用 Person.people.all() 会返回所有的 Person 对象列表。

自定义管理器

你可以通过扩展 Manager 基类并在模块中把它实例化来得到一个定制的 Manager 。

需要定制 Manager 的原因通常有两个:要添加新的 Manager 方法,或者需要修改 Manager返回的原始的 QuerySet 。

添加额外的管理器方法

增加附加的 Manager 方法是在模型中增加数据表级别的功能的首选方法。(对于行级别的功能——就是作用于模型的单个实例上的功能——要使用模型方法(下面有介绍),而不是定制的 Manager 方法。)

你可以通过定制 Manager 方法来返回任何你需要的东西,而不一定要返回一个 QuerySet 。

例如,下面的定制的 Manager 提供了一个叫 with_counts() 的方法,用于返回 OpinionPoll对象的列表,而每个对象又拥有一个 num_responses 属性,记录合计数量的结果。

from django.db import connection class PollManager(models.Manager):

def with_counts(self):

cursor = connection.cursor() cursor.execute("""

SELECT p.id, p.question, p.poll_date, COUNT(*) FROM polls_opinionpoll p, polls_response r WHERE p.id = r.poll_id

GROUP BY 1, 2, 3 ORDER BY 3 DESC""")

result_list = []

for row in cursor.fetchall():

p = self.model(id=row[0], question=row[1], poll_date=row[2]) p.num_responses = row[3]

result_list.append(p) return result_list

class OpinionPoll(models.Model):

question = models.CharField(maxlength=200) poll_date = models.DateField()

objects = PollManager()

class Response(models.Model):

poll = models.ForeignKey(Poll)

person_name = models.CharField(maxlength=50) response = models.TextField()

在这个例子中,你通过调用 OpinionPoll.objects.with_counts() 来返回的所有的 OpinionPoll 对象都拥有一个 num_responses 属性。

这个例子中另外一个需要注意的事情是 Manager 的方法可以通过 self.model 来访问它所依附的模型类。

修改初始的管理器查询集

Manager 的默认的 QuerySet 返回系统中的所有对象。例如,看这个模型: class Book(models.Model):

title = models.CharField(maxlength=100) author = models.CharField(maxlength=50)

通过调用 Book.objects.all() 可以得到数据库里的所有书籍记录。

你可以通过覆盖 Manager.get_query_set() 方法来改写默认地 QuerySet 。

get_query_set() 应该返回一个包含所需属性的 QuerySet 。

例如:下面的模型有 两个 管理器:一个返回所有的对象,另一个只返回 Roald Dahl 著作的书籍。

# First, define the Manager subclass. class DahlBookManager(models.Manager):

def get_query_set(self):

return super(DahlBookManager, self).get_query_set().filter(author='Roald

Dahl')

# Then hook it into the Book model explicitly. class Book(models.Model):

title = models.CharField(maxlength=100) author = models.CharField(maxlength=50)

objects = models.Manager() # The default manager. dahl_objects = DahlBookManager() # The Dahl-specific manager.

在这个示例模型中, Book.objects.all() 会返回数据库中的所有书籍,但

Book.dahl_objects.all() 只返回 Roald Dahl 著作的书籍。

当然,由于 get_query_set() 返回一个 QuerySet 对象,你就可以对它使用 filter() 、

exclude() 以及其他的 QuerySet 方法。因而,这些语句都是合法的:

Book.dahl_objects.all() Book.dahl_objects.filter(title='Matilda') Book.dahl_objects.count()

这个例子也涉及了另外一个有趣的技术:对同一个模型使用多个管理器。你可以在一个模型上附加任意多个 Manager() 实例。这是给模型定义通用过滤器的便捷方法。看这个例子:

class MaleManager(models.Manager): def get_query_set(self):

return super(MaleManager, self).get_query_set().filter(sex='M')

class FemaleManager(models.Manager): def get_query_set(self):

return super(FemaleManager, self).get_query_set().filter(sex='F')

class Person(models.Model):

first_name = models.CharField(maxlength=50) last_name = models.CharField(maxlength=50)

sex = models.CharField(maxlength=1, choices=(('M', 'Male'), ('F', 'Female'))) people = models.Manager()

men = MaleManager() women = FemaleManager()

这个例子让你可以通过调用 Person.men.all() 、 Person.women.all() 和

Person.people.all() 来产生更易理解的结果。

假如你使用客製化的管理者物件,要注意,第一個管理者,Django 遇到(在 order by 他們在模型裏已被定義)有一個特別的狀態。Django 翻譯這第一個 Manager 定義在一個類別裏是預設的管理者。當然的操作,如 Djangos 管理站使用這個預設的 Manager,來取得一系列的物件,所以它是一個好點子,對於第一個 Manager 是相對未過濾。在最後的例子,這個 people

Manager 也是定義在第一個,所以它是預設的 Manager,

模型方法

自定义 model 的方法可以为你的 model 对象提供行级的操作功能。Whereas Manager methods are intended to do tablewide things, model methods should act on a particular model instance.

这是一个很有价值的技术,它有利于你把业务逻辑统一放到一个地方,这个地方就是:model.例如:model 中有一些自定义的方法。

class Person(models.Model):

first_name = models.CharField(maxlength=50) last_name = models.CharField(maxlength=50) birth_date = models.DateField()

address = models.CharField(maxlength=100) city = models.CharField(maxlength=50)

state = models.USStateField() # Yes, this is America-centric...

def baby_boomer_status(self):

"""Returns the person's baby-boomer status.""" import datetime

if datetime.date(1945, 8, 1) <= self.birth_date <= datetime.date(1964, 12,

31):

return "Baby boomer"

if self.birth_date < datetime.date(1945, 8, 1): return "Pre-boomer"

return "Post-boomer"

def is_midwestern(self):

"""Returns True if this person is from the Midwest."""

return self.state in ('IL', 'WI', 'MI', 'IN', 'OH', 'IA', 'MO')

@property

def full_name(self):

"""Returns the person's full name."""

return '%s %s' % (self.first_name, self.last_name)

最後一個方法,在這個例子,是屬性,一個特性由客製的 gtter/setter 使用者的源碼來實作。屬性是一個重要的技巧,被加入在 Python 2.2;你可以讀到更多關於這個屬性,在此 http://www.python.org/download/releases/2.2/descrintro/#property`_.

還有一堆手動的模型方法,對 Python or Django 有特別的意義。 這些方法在下面的段落裏會描述。

str

__str__()是一個 Python 魔術的方法,它定義了,什麼東名必須被回傳假如你呼叫 str()在這個物件。Django 使用 str(obj)(或是相對應的函數,unicode(obj),簡短地描述),在很多地方,最有名,是這秀出來的值被這個物件重繪在 Django 管理站,而且被寫入樣板的值,當它展示一個物件。因此,你必須總是返回一個好的,人類可讀的字串,對這個物件__str 。即使這不是必須的,它還是強 列地被鼓勵 。

這裏是一個範例:

class Person(models.Model):

first_name = models.CharField(maxlength=50) last_name = models.CharField(maxlength=50)

def

__str__(self):

return '%s %s' % (self.first_name, self.last_name)

get_absolute_url

可以通过定义 get_absolute_url() 方法来告诉 Django 怎样得到一个对象的 URL,例如: def get_absolute_url(self):

return "/people/%i/" % self.id

Django 使用這個在它的管理介面。假如一個物件定義了 get_absolute_url(),這物件編輯的頁面將有一個視圖在站上的聯結獎會帶領你直接地往這個物件的公開的視圖,根據 get_absolute_url()

另外,一堆 Django 其他的小地方,如 syndication-feed 框架,使用 get_absolute_url(),當做一個方便的提醒人們已定義過這個方法。

相对于写死了你的对象所处于的 URL 来讲,在模板中使用 get_absolute_url() 是一个很好的习惯。例如,下面这个例子的写法是很不好:

<a href="/people/{{ object.id }}/">{{ object.name }}</a>但这段模板代码就很优雅:

<a href="{{ object.get_absolute_url }}">{{ object.name }}</a>

當我們這樣用,只寫 get_absolute_url(),問題是,它輕微的破壞 DRY 原理:這物件的 URL被同時定義在 URLconf 檔和模型裏。

你可以進一步的解構你的模型,從 URLconf ,使用 permalink 裝飾詞。這 decorator 被傳入一個 view 函數,一系列的定位參數,而且(可選擇的)一個字典叫做命名的參數。Django 可以正確的走完整的URL 路徑,藉著URLconf,替代你已經給URL 的參數。例如,假如你的URLconf擁有一行,如下:

(r'^people/(\d+)/$', 'people.views.details'),

你的模型里的 get_absolute_url 方法可以像下面这样写:

@models.permalink

def get_absolute_url(self):

return ('people.views.details', [str(self.id)])与此类似,如果有这样的一个 URLconf:

(r'/archive/(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/$', archive_view)

你可以像下面那样用 permalink()来引用这个链接:

@models.permalink

def get_absolute_url(self): return ('archive_view', (), {

'year': self.created.year, 'month': self.created.month, 'day': self.created.day})

注意,我們指出一個空的序列,在這種案例的第二個參數,因為我們想要傳入只有關鍵字的參數,不是已命名的參數。

用這個方法,你可以試著用模型的絕對 URL ,指向 view ,被用來展示它, 而不要在任何地方重覆 URL 訊息。你仍然可以使用 get_absolute_url 方法,在樣板裏,就像之前一樣

执行定制的 SQL

請自在的寫客製的 SQL 句子在客製的模型方法,和模組層級的方法。 這個物件,

django.db.connection 展示了現行的資料庫連接。要使用它,直接呼叫 connection.cursor()來獲得一個 cursor 物件。然後,呼叫 cursor.execute(sql, [params])來執行一段 SQL,和

cursor.fetchone()或是 cursor.fetchall()來傳回結果資料列:

def my_custom_sql(self):

from django.db import connection cursor = connection.cursor()

cursor.execute("SELECT foo FROM bar WHERE baz = %s", [self.baz]) row = cursor.fetchone()

return row

connection and cursor 最常被實作,在標準的 Python DB-API (http://www.python.org/peps/pep-0249.html). 假如你還不夠熟悉 Python DB-API,注意在 cursor.execute()SQL 句子。使用 placeholders,%s,甚於直接在 SQL 裏加參數。假如你使用這個技巧,底下的資料庫函式庫將自動的加上引號給你的參數,視需要而 定。(也注意

Django 期待%splaceholder 而不是?placeholder,後者用於 SQLite Python 連接。這是為了穩定性的考量。

最後的註記:假如你只是想要使用一個客製的 WHERE 語句,你可以只用 where,tables,params參數給這個標準的 lookup API.請看附錄 C.

覆盖默认的 Model 方法

如附錄 C 所解釋的,每一個模型自動獲得少數的方法,有名的,如 save()和 delete()。你可以覆寫這些方法來改變行為。

一個古老的使用者案例:覆寫內建的方法,假如你想要一些事情發生,當你要存入一個物件,例如:

class Blog(models.Model):

name = models.CharField(maxlength=100) tagline = models.TextField()

def save(self): do_something()

super(Blog, self).save() # Call the "real" save() method. do_something_else()

你也可以阻止保存:

class Blog(models.Model):

name = models.CharField(maxlength=100) tagline = models.TextField()

def save(self):

if self.name == "Yoko Ono's blog":

return # Yoko shall never have her own blog! else:

super(Blog, self).save() # Call the "real" save() method

Admin 选项

Admin 类告诉 Django 如何在管理站点中显示模块。

以下的段落展示了一系列的所有可能的 Admin 選項。沒有一個選項是必選的。為了使用一個管理者介面,而不要指定任何選項,請用 pass,像這樣:

class Admin: pass

加上 class Admin 到一個模型真的是可選的。

date_hierarchy

設定 date_hierarchy 到你模型裏的 DateField 或是 DateTimeField,然後修改清單的頁面將會包含一個使用這個欄位的 date-based 的瀏覽

這裏有個例子:

class CustomerOrder(models.Model): order_date = models.DateTimeField()

...

class Admin:

date_hierarchy = "order_date"

fields

設定 fields 來控制管理畫面的輸出,加上,修改頁面

欄位,是一個非常複雜巢狀的資料結構 ,可以很好的被一個範例展示。以下是擷取自FlatPage模型,這是 django.contrib.flatpages 的一部分

class FlatPage(models.Model):

...

class Admin:

fields = (

(None, {

'fields': ('url', 'title', 'content', 'sites')

}),

('Advanced options', { 'classes': 'collapse',

'fields' : ('enable_comments', 'registration_required',

'template_name')

}),

)

型式上,fields 是一個串列:由兩個 tuples 組成,在其中,每一組 two-tuple 呈現一個

<fieldset>在 admin 表單頁。一個<fieldset>是表單的一個段落。

這個 two-tuples 都用這種型式,(name, field_options),在這裏,name 是一個字串表示是

fieldset 的名稱,而 field_options 是資訊字典,fieldset,包含一系列要展示的欄位。

If fields isnt given, Django will default to displaying each field that isnt an AutoField and has editable=True , in a single fieldset, in the same order as the fields are defined in the model.

“field_options”字典拥有将在下面的章节中描述的关键字。 fields

给字段的元组命名,以方便显示在这个字段集中。这个关键字是必需的。

在一行里面显示多个字段,并且将这些字段装在它们自己的元组里。在这个例子里,

“first_name”和“last_name”字段将显示在同一行中。

'fields': (('first_name', 'last_name'), 'address', 'city', 'state'), classes

A string containing extra CSS classes to apply to the fieldset.通过空格分开已使用多个类:

'classes': 'wide extrapretty',

Two useful classes defined by the default admin site stylesheet are collapse and wide . Fieldsets with the collapse style will be initially collapsed in the admin site and replaced with a small click to expand link. Fieldsets with the wide style will be given extra horizontal space.

description

A string of optional extra text to be displayed at the top of each fieldset, under the heading of the fieldset. Its used verbatim, so you can use any HTML and you must escape any special HTML characters (such as ampersands) yourself.

js

A list of strings representing URLs of JavaScript files to link into the ad min screen via <script src=""> tags. This can be used to tweak a given type of admin page in JavaScript or to provide quick links to fill in default values for certain fields.

If you use relative URLs that is, URLs that dont start with http:// or / then the admin site will automatically prefix these links with settings.ADMIN_MEDIA_PREFIX .

list_display

Set list_display to control which fields are displayed on the change list page of the admin.

If you dont set list_display , the admin site will display a single column that

displays the __str () representation of each object.

这里是一些专门关于``list_display``的例子:

If the field is a ForeignKey , Django will display the str () of the related object.

ManyToManyField fields arent supported, because that would entail executing a separate SQL statement for each row in the table. If you want to do this nonetheless, give your model a custom method, and add that methods name to list_display . (More information on custom methods in list_display shortly.)

If the field is a BooleanField or NullBooleanField , Django will display a pretty on or off icon instead of True or False .

If the string given is a method of the model, Django will call it and display the output. This method should have a short_description function attribute, for use as the header for the field.

以下是一个完整的例子模型: class Person(models.Model):

name = models.CharField(maxlength=50)

birthday = models.DateField()

class Admin:

list_display = ('name', 'decade_born_in') def decade_born_in(self):

return self.birthday.strftime('%Y')[:3] + "0's" decade_born_in.short_description = 'Birth decade'

If the string given is a method of the model, Django will HTML-escape the output by default. If youd rather not escape the output of the method, give the method an allow_tags attribute whose value is True .

以下是一个完整的例子模型: class Person(models.Model):

first_name = models.CharField(maxlength=50)

last_name = models.CharField(maxlength=50) color_code = models.CharField(maxlength=6)

class Admin:

list_display = ('first_name', 'last_name', 'colored_name')

def colored_name(self):

return '<span style="color: #%s;">%s %s</span>' % (self.color_code, self.first_name, self.last_name)

colored_name.allow_tags = True

If the string given is a method of the model that returns True or False , Django will display a pretty on or off icon if you give the method a boolean attribute whose value is True .

以下是一个完整的例子模型: class Person(models.Model):

first_name = models.CharField(maxlength=50)

birthday = models.DateField()

class Admin:

list_display = ('name', 'born_in_fifties')

def born_in_fifties(self):

return self.birthday.strftime('%Y')[:3] == 5 born_in_fifties.boolean = True

The __str__() methods are just as valid in list_display as any other model method,

so its perfectly OK to do this:

list_display = ('__str__', 'some_other_field')

Usually, elements of list_display that arent actual database fields cant be used in sorting (because Django does all the sorting at the database level).

However, if an element of list_display represents a certain database field, you can indicate this fact by setting the admin_order_field attribute of the item, for example:

class Person(models.Model):

first_name = models.CharField(maxlength=50) color_code = models.CharField(maxlength=6)

class Admin:

list_display = ('first_name', 'colored_first_name')

def colored_first_name(self):

return '<span style="color: #%s;">%s</span>' % (self.color_code, self.first_name)

colored_first_name.allow_tags = True colored_first_name.admin_order_field = 'first_name'

The preceding code will tell Django to order by the first_name field when trying to sort by colored_first_name in the admin site.

list_display_links

Set list_display_links to control which fields in list_display should be linked to the change page for an object.

By default, the change list page will link the first column the first field specified in list_display to the change page for each item. But list_display_links lets you change which columns are linked. Set list_display_links to a list or tuple of field names (in the same format as list_display ) to link.

list_display_links can specify one or many field names. As long as the field names appear in list_display , Django doesnt care how many (or how few) fields are linked. The only requirement is that if you want to use list_display_links , you must define list_display .

在这个例子中,“first_name”和“last_name”将被链接到更改列表页 class Person(models.Model):

...

class Admin:

list_display = ('first_name', 'last_name', 'birthday') list_display_links = ('first_name', 'last_name')

Finally, note that in order to use list_display_links , you must define list_display , too.

list_filter

Set list_filter to activate filters in the right sidebar of the change list page of the admin interface. This should be a list of field names, and each specified field should be either a BooleanField , DateField , DateTimeField , or ForeignKey .

This example, taken from the django.contrib.auth.models.User model, shows how both list_display and list_filter work:

class User(models.Model):

...

class Admin:

list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff') list_filter = ('is_staff', 'is_superuser')

list_per_page

Set list_per_page to control how many items appear on each paginated admin change list page. By default, this is set to 100 .

list_select_related

Set list_select_related to tell Django to use select_related() in retrieving the list of objects on the admin change list page. This can save you a bunch of database queries if youre using related objects in the admin change list display.

The value should be either True or False . The default is False unless one of the list_display fields is a ForeignKey .

关于“select_related()”的更多信息,参见附录 C。

ordering

Set ordering to specify how objects on the admin change list page should be ordered. This should be a list or tuple in the same format as a models ordering parameter.

If this isnt provided, the Django admin interface will use the models default ordering.

save_as

Set save_as to True to enable a save as feature on admin change forms.

Normally, objects have three save options: Save, Save and continue editing, and Save and add another. If save_as is True , Save and add another will be replaced by a Save as button.

Save as means the object will be saved as a new object (with a new ID), rather than the old object.

默认情况下,“save_as”设置成“False”

save_on_top

Set save_on_top to add save buttons across the top of your admin change forms.

Normally, the save buttons appear only at the bottom of the forms. If you set save_on_top , the buttons will appear both on the top and the bottom.

默认情况下,“save_on_top”设置成“False”

search_fields

Set search_fields to enable a search box on the admin change list page. This should be set to a list of field names that will be searched whenever somebody submits a search query in that text box.

These fields should be some kind of text field, such as CharField or TextField . You can also perform a related lookup on a ForeignKey with the lookup API follow notation:

class Employee(models.Model):

department = models.ForeignKey(Department)

...

class Admin:

search_fields = ['department name']

When somebody does a search in the admin search box, Django splits the search query into words and returns all objects that contain each of the words, case insensitive,

where each word must be in at least one of search_fields . For example, if search_fields is set to ['first_name', 'last_name'] and a user searches for john lennon , Django will do the equivalent of this SQL WHERE clause:

WHERE (first_name ILIKE '%john%' OR last_name ILIKE '%john%') AND (first_name ILIKE '%lennon%' OR last_name ILIKE '%lennon%')

For faster and/or more restrictive searches, prefix the field name with an operator, as shown in Table B-7.

表 B-7. search_fields 中允许使用的操作符

操作符

含义

^

匹配字段的开头。例如,把 search_fields 设置成 ['^first_name', '^last_name'] ,当用户搜索 john lennon 时,Django 相当于执行了这样的 SQL WHERE语句:

WHERE (first_name ILIKE 'john%' OR last_name ILIKE 'john%') AND (first_name ILIKE 'lennon%' OR last_name ILIKE 'lennon%')

这个查询要比执行普通的 '%john%' 查询效率高,因为数据库只需要检查每一列数据

的开头,而不用把整 列数据都扫一遍。此外,如果有针对这一列的索引的话,某些数据库可能会在查询中使用索引,即使它是一个 LIKE 查询。

=

精确匹配,不区分大小写。例如,把 search_fields 设置成 ['=first_name', '=last_name'] ,当 用户搜索 john lennon 时,Django 相当于执行了这样的 SQL

WHERE 语句:

WHERE (first_name ILIKE 'john' OR last_name ILIKE 'john') AND (first_name ILIKE 'lennon' OR last_name ILIKE 'lennon')

记住,搜索输入是靠空格来分隔的,所以,在这个例子中还不可能找出 first_name 恰恰是 'john winston' (中间有空格)的所有记录。

@

执行全文匹配。这个和默认的搜索方法类似,但是它使用索引。目前只在 MySQL 中可用。