编写你的第一个Django应用,第1部分

让我们通过例子来学习。

在这第1部分教程中,我们会建立一个基本的投票应用。

它包含了两部分:

  • 一个公共的站点,可以进行投票和查看投票的结果。
  • 一个管理站点,让管理员来添加、修改和删除选票。

我们假定你已经 安装好Django 。你可以用下面的命令来查看安装的Django的版本:

$ python -c "import django; print(django.get_version())"

如果已经安装好Django,你将看到安装的Django的版本号,否则,你会看到一个错误提示: “ImportError: No module named django (找不到django模块)”。

本教程是用Django 1.8 和 Python 3.2 以上版本。如果安装的DJango版本不符合,你可以在本页面右下角查询对应于你安装的Django版本的教程,或者升级你的Django到最新版本。如果你仍然使用的是Python 2.7,你需要调整例子中的部分代码,在代码注释中会有注明。

怎样安装Django 中有介绍怎样卸载旧版本Django、安装新版本的Django。

哪里能获取帮助:

如果你在学习本教程中遇到了麻烦,你可以在 django-users 提交问题,或者在 #django on irc.freenode.net 中会有其它Django用户能帮助你。(在我们大天朝,可以加入一些吹水的QQ群呀,当然也有一些高级而又热心的用户还是会HELP YOU)

创建一个项目

如果这是你第1次接触Django,你需要注意一些在初始化项目时的步骤。也就是说,在新开始一个 项目 时需要运行几个Django命令来自动生成项目初始化代码-包含一个Django实例的相关配置:包括数据库设置,Django相关配置项和应用相关设置置项。

从命令行,cd 进入到存放代码的目录中,运行下列命令:

$ django-admin startproject mysite

这将在你当前目录下创建一个 mysite 目录,如果该命令没有正常工件,请查看 django-admin故障排除.

注解

你需要避免将项目命名为Python内部专有名称和Django组件名。简单地说,你就不应将项目命名为 django (和Django相冲突)或者 test (和Python集成模块名冲突)

代码应该存储在哪里?

如果你曾使用过PHP较早期项目(不是现在流行的框架),你或许会将代码放在Web服务器的文档根目录下(比如 /var/www 目录下)。但是对于Django,你不需要这样做。将Python代码放到Web服务器的文档目录下并不是好的方式,因为这样存在很大的风险:很可能会将Python代码透过Web暴露到网络上,这样做非常不安全。

将代码存放到文档目录 之外 ,比如 /home/mycode

让我们在看一下 startproject 新创建的项目生成的目录结构:

mysite/
    manage.py
    mysite/
        __init__.py
        settings.py
        urls.py
        wsgi.py

这些文件分别是:

  • 最外层的 mysite/ 根目录仅仅是你项目的容器。Django并不乎这个目录的名字,可以随意修改该目录名。
  • manage.py: 一个命令行的工具,它实现了与Django项目进行交互的多种方式,关于 manage.py更多使用详情
  • 里层的 mysite/ 目录是项目的一个Python软件包,你将在导出此目录中的任何东西时使用到这个名字(比如 mysite.urls)。
  • mysite/__init__.py: 这是一个空文件,作用是让Python将该目录作为一个Python的包(关于 更多关于包 在Python的官方文档中在详细介绍)
  • mysite/settings.py: 该Django项目的配置文件。关于如何 正确的配置
  • mysite/urls.py: 该文件是Django项目的URL路由配置;是你Django站点的目录表,更多关于 路由配置
  • mysite/wsgi.py: 是你Django项目的WSGI兼容web服务器的入口,连接你的项目与Web服务器,在 部署环境 可以了解更多详情。

数据库设置

现在,编辑 mysite/settings.py,它是一个普通的Python模块,包含了关于配置Django的一些模块级变量。

默认情况下,配置使用的是 SQLite 数据库。如果你是数据库方面的新手,或者你仅仅想尝试下Django,这就是最简单的选择。Python包含了SQLite,所以你不需要为支持该数据库做任何安装。但在你开始真正一个项目时,你可能就会想用一个更多功能的大型数据库(比如PostgreSQL),这样可以避免在切换数据库遇到的头痛问题。

如果你希望使用另一种数据库,需要安装适配的 数据库插件,修改下面几项 DATABASES 'default' 栏目来适配到你的数据库设置:

  • ENGINE – 可选的数据库引擎有 'django.db.backends.sqlite3''django.db.backends.postgresql_psycopg2''django.db.backends.mysql', 或者 'django.db.backends.oracle'。 还有 其它适用的第3方插件
  • NAME – 数据库名。如果你使用的是 SQLite,数据库将是电脑上某个文件;此时,NAME 应该是包含该文件名的绝对路径。默认是 os.path.join(BASE_DIR, 'db.sqlite3') 存储数据库文件到项目目录下。

如果你使用的不是SQLite数据库, 需要另外设置用户名、密码和主机 USER, PASSWORD, HOST 。更多详情,请看参考文档 DATABASES

注解

如果你使用PostgreSQL或者MySQL,确保你已经为本项目建立了数据库, 一般是在数据库的交互命令提示符下执行 “CREATE DATABASE database_name;” 。

如果你使用的是SQLite,你不需要动手创建数据库-数据库文件会在需要的时候自动创建。

在你编辑 mysite/settings.py 的时候,把 TIME_ZONE 设置为你所在的时区。

另外,注意在配置文件顶部的 INSTALLED_APPS ,在该项中包含的是在Django实例中激活的所有Django应用名字,每个应用都能够在多个项目中使用,你可以将应用单独打包并分发到其它项目中。

默认情况下, INSTALLED_APPS 包含了由Django提供的以下几项应用:

默认情况下,这些应用都会包含到新创建的项目中。

大部分应用都会至少使用到一个数据库表,所以,我们需要在之前先创建好这个数据库。下面的命令就是创建应用对应的数据库:

$ python manage.py migrate

migrate 命令会按照 mysite/settings.py 配置文件中的 INSTALLED_APPS 包含的应用中的模型来创建其对应的数据库表,还会检测应用中模型的变化来修改、迁移数据库表(后面教程中会有详细的讲解)。每一次数据模型变化带来的数据迁移都会给用户一条提示消息。如果你有兴趣,在数据库客户端运行这几个命令 \dt (PostgreSQL), SHOW TABLES; (MySQL), 或者 .schema (SQLite) 会看到详细的数据表创建信息。

For the minimalists

正如我们上面所说,那些默认包含到新创建项目中的应用并不是所有人都真正需要,所以你不需要这些默认应用时,在运行命令 migrate 之前可以在 INSTALLED_APPS 中进行注释或者删除掉, migrate 命令只会对 INSTALLED_APPS 中包含的应用运用迁移。

开发服务器

现在我们来检验Django项目能否正常运行。进入到外层的项目目录 mysite 下,运行下面的命令:

$ python manage.py runserver

你将看到命令行显示如下信息:

Performing system checks...

0 errors found
February 23, 2017 - 15:50:53
Django version 1.8, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

这样就开启了Django开发服务器, 一个用Python开发的轻量级的Web服务器-Django自带的开发服务器。和生产环境下的Web服务器(比如apache)不同的是,在部署到生产环境之前,开发服务器不需要做任何配置。

现在需要说明一下: 一定不要 使用开发服务器用于生产环境,这仅仅是作为在开发环境下使用。(Web框架只是用于快速开发,而不是真正的Web服务器。)

现在服务已经正常运行,在浏览器中输入 http://127.0.0.1:8000/ 你将看到一个 “Welcome to Django” 页面,带有浅蓝色、明快色彩的标题”It worked!”。

Changing the port

默认情况下, runserver 命令将侦听开发服务器本地IP地址的8000端口。

如果你想侦听不同的端口,在该命令的参数中指定新的端口号。假如你想侦听的是8080端口:

    $ python manage.py runserver 8080

如果你想侦听开发服务器的其它IP地址,在命令的参数中指定新的IP地址,地址后面是端口号。所以你要侦听所有网卡上的IP地址(希望其它电脑也能访问)时,使用:
    $ python manage.py runserver 0.0.0.0:8000

关于开发服务器的更详细的文档在 :djadmin:`runserver` 。

自动重新加载 runserver

开发服务器能对每一个请求进行自动加载Python代码。当你修改了代码时不需要手动重启开发服务器,开发服务器自动检测到代码变化后会自动重新加载代码,即代码被修改后自动生效。但是有些操作,比如添加了新的文件时,并不会触发开发服务器的自动加载功能,所以在这种情况下需要手动重启开发服务器。

创建模型

现在,项目环境已经建立好了,你可以开始工作了。

你写的每一个Django应用都是具有明确标准的一个独立的Python包。Django拥有自动生成应用的基本目录结构的一套工具,你不需要为如何建立应用的目录而费心,所以你能更加关注于你的代码。

项目 vs. 应用

项目和应用之间的区别是什么?一个应用是一个 Web程序-比如一个博客系统,一个数据库的公共记录器,或者一个简单的投票程序。一个项目是一系列配置和一些应用的合集组成的一个Web站点。一个项目可以包含多个应用,一个应用可以被多个项目使用。

应用可以存放在 Python path 包含的任意一个目录位置中。在本教程中,我们新建的投票应用存放在 manage.py 文件同一级目录下,这样我们可以将它作为顶级模块来导出,而不是作为 mysite 的一个子模块。

新建应用时,确定你是在 manage.py 文件所在的目录下,然后输入下面的命令:

$ python manage.py startapp polls

这样就建立了一个目录 polls , 该目录结构如下:

polls/
    __init__.py
    admin.py
    migrations/
        __init__.py
    models.py
    tests.py
    views.py

这个目录包含了投票应用的全部文件、目录结构。

编写一个数据库驱动的Web应用的第一步是定义应用的模型,本质上就是你的数据库结构和相应的数据表元数据信息。

哲学

一个模型是一个单独的、对应于真实数据库的完整源代码,它包含了数据表字段及需要存储到数据库中的所有相关信息。Django遵循 DRY 规则 ,目标是一次定义,重复使用。

具有的数据迁移功能 - 与Ruby On Rails不同,举例来说,按照应用的模型所在的文件,完整记录了能够回滚到任何一个数据库历史的各种数据信息。

在投票应用这个简单的例子中,我们创建了两个模型: QuestionChoice
Question 包含一个问题和一个发布上期, Choice 包含两个字段: 选择的文件内容和投票得分。每一个 Choice 都关联到一个 Question

以上构想通过一个独立的Python类来表现,编辑 polls/models.py 文件,包含如下内容:

polls/models.py
from django.db import models


class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')


class Choice(models.Model):
    question = models.ForeignKey(Question)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

代码非常简显易懂。每一个模型都是用 django.db.models.Model 子类来描述。每一个模型都包含一系列的类属性-分别对应于数据库表的一个字段。

每一个模型类的属性都是用 Field 类的实例来表示 – 比如 CharField 是对应于字符串字段,DateTimeField 对应是日期字段。Django能够通过这个属性,正确的对应到数据字段的属于哪个类型。

每一个 Field 类实例的名字 (比如 question_text 或者 pub_date) 都是一个字段名,这是一种机器友好识别的格式。在代码中用类实例名字,来引用其在数据库中的代表的字段。

你可以使用 Field 的第一个可选参数来定义一个用户易读(用户友好方式)的名字,这被用于Django内省部分,同时也作为文档。

如果这个类实例未提供该参数,Django将使用机器易读的名字,在这个例子中,我们仅仅为 Question.pub_date 实例定义一个用户友好可读的名字,而模型中的其它实例将使用机器易读的名字来作为用户易读方式的替代。

有些 Field 类需要提供一个必选参数项,像 CharField 就需要提供一个属性 max_length 。这个必选参数与数据库表无关,只是作为Django验证数据用,等一会我们会讲到。

另外 Field 还提供了可选的参数项(如某个实例项的默认值),在上面实例中,我们设置了 :attr: ~django.db.models.Field.Default 为0表示投票的默认值为0。

最后,注意一下数据关联关系的定义,使用的是 ForeignKey。它意思是告诉 Django 每一项 Choice 单独关联到一个 Question。Django支持所有通用数据库中的几种关联关系: 多对一,多对多,一对一。

激活模型

模型中的代码只有很少几行,但是Django用这些代码能产生大量的信息,上面的模型表示:

  • 为应用建立数据库表 (CREATE TABLE 语句) 。
  • 创建访问 QuestionChoice 对象的数据库API。

为应用创建好模型后,首先需要告诉Django我们创建的应用名 polls

哲学

Django应用是可 插拔 的:你可以在多个项目中使用同一个应用,还可以发布你的应用,因为应用不必绑定到一个安装好的django项目中。

再次编辑 mysite/settings.py 文件,修改 INSTALLED_APPS 设置,包含 'polls',修改好后看起来像下面这样:

mysite/settings.py
INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'polls',
)

现在Django知道我们创建了 polls 应用,运行下面的命令:

$ python manage.py makemigrations polls

你将看到类似下面的信息:

Migrations for 'polls':
  0001_initial.py:
    - Create model Question
    - Create model Choice
    - Add field question to choice

运行 makemigrations 命令,就是告诉 Django你对模型作了修改(在这里,你新创建了一个应用的模型),你希望将修改 迁移migration 应用到数据库中。

迁移就是Django在你对模型作了修改后(以便修改数据库表),以磁盘文件的形式保存每一次变化细节。如果你想查看模型的迁移数据,其文件是 polls/migrations/0001_initial.py。你不用担心:不是在每次修改模型后都得查看这些迁移文件,将迁移数据设计为用户可编辑的文本文件(每一次迁移都会保存为一个文件)是为了方便你随时查看Django都作了哪些修改。

有个名为 migrate 的命令将迁移自动应用于数据库表中,我们等一会儿就会看到。现在我们需要了解下数据迁移时是通过哪些SQL语句来实现的。sqlmigrate 命令可以加上迁移的应用名字作为参数,它返回SQL语句如下:

$ python manage.py sqlmigrate polls 0001

你将看到类似于以下形式的信息(以更易读的形式进行了格式处理):

BEGIN;
CREATE TABLE "polls_choice" (
    "id" serial NOT NULL PRIMARY KEY,
    "choice_text" varchar(200) NOT NULL,
    "votes" integer NOT NULL
);
CREATE TABLE "polls_question" (
    "id" serial NOT NULL PRIMARY KEY,
    "question_text" varchar(200) NOT NULL,
    "pub_date" timestamp with time zone NOT NULL
);
ALTER TABLE "polls_choice" ADD COLUMN "question_id" integer NOT NULL;
ALTER TABLE "polls_choice" ALTER COLUMN "question_id" DROP DEFAULT;
CREATE INDEX "polls_choice_7aa0f6ee" ON "polls_choice" ("question_id");
ALTER TABLE "polls_choice"
  ADD CONSTRAINT "polls_choice_question_id_246c99a640fbbd72_fk_polls_question_id"
    FOREIGN KEY ("question_id")
    REFERENCES "polls_question" ("id")
    DEFERRABLE INITIALLY DEFERRED;

COMMIT;

说明如下:

  • 具体的输出内容将依赖于你所使用的数据库。上面例子中使用的是PostgreSQL。
  • 数据表名字是自动生成的,命名规则是以应用名(polls), 模型名字的小写字母(question, choice),中间以下划线 _ 相连接。(当然你可以用喜欢的名字来作为数据表名字)
  • 每个模型会自动添加一个属性id,并且作为主健(IDs),其值是自动增加。(也可以任意指定一个属性作为主键)。
  • 作为约定,如果一个模型属性是外键引用到另一个模型中的主键时,该属性名自动以 "_id" 作为后缀。 (这个后缀名可以自定义)。
  • 以主键作为外键引用是为了更加清晰明白。不要担心 延缓 部分,这只是让PostgreSQL在执行前不用强行指定外键。
  • 会根据你使用的数据库作部分调整。像数据库特殊字段类型,比如 auto_increment (MySQL), serial (PostgreSQL), 或者 integer primary key autoinrement (SQLite) 都是作为自动字段的属性。有些数据库会给字段名加上引号-比如双引号或者单引号。
  • 这个 sqlmigrate 命令不会真正迁移数据到数据库中,它只是在屏幕上显示Django将要对数据库采取哪些操作。这些信息在你想检查Django的下一步操作、或者是数据库管理员需要SQL修改脚本时很有用。

如果你有兴趣,还可以运行 python manage.py check ; 它可以检查项目中除数据迁移和数据库操作之外的其它一切问题。

现在,再次运行 migrate 将按模型在数据库中创建对应的数据库表。

$ python manage.py migrate
Operations to perform:
  Synchronize unmigrated apps: staticfiles, messages
  Apply all migrations: admin, contenttypes, polls, auth, sessions
Synchronizing apps without migrations:
  Creating tables...
    Running deferred SQL...
  Installing custom SQL...
Running migrations:
  Rendering model states... DONE
  Applying <migration name>... OK

迁移命令 migrate 会将尚未应用的迁移数据应用到数据库中 (Django在数据库中为应用设计了一个名为 django_migrations 的数据迁移跟踪记录表,重复运行这个命令不会对数据库作任何修改,仅仅是在检测到模型有了变化后,才会将差异同步到数据库中。

迁移非常强大,它可以在你每次修改模型后、项目的整个开发过程中,无需对数据库表作修改、删除、重建。它能够实时地升级你的数据库表,不丢失任何数据。我们将在后面教程中深入讲解,但是现在,记住在修改模型后的3步操作:

将创建迁移数据、应用迁移的命令各自单独分开的原因是你很可能需要将迁移数据记录随着应用记录到版本控制系统中,这不仅可以简化你的开发过程,还有助于项目中的其它开发者。

更多关于项目管理 manage.py 方面的信息,请查阅 django-admin docuentation 文档。

玩弄API

现在我们进入交互式的 Python shell 命令行,玩一下Django提供的API。用这个命令进入到Python shell:

$ python manage.py shell

我们使用这样的命令,而不是简单的输入 “python”,因为 manage.py 设置了 DJANGO_SETTINGS_MODULE 环境变量,为Django清晰的指明了 Python 导出路径为 mysite/settings.py 这个文件。

Bypassing manage.py

如果你不想使用 manage.py,也可以。在环境变量中设置 DJANGO_SETTINGS_MODULEmysite.settings,然后运行Python shell,再设置:

>>> import django
>>> django.setup()

如果引发了错误 AttributeError,你或许使用的不是匹配本教程对应版本的Django。你要么是使用旧版本的教程,要么是升级到新版本的Django。

必须是在和 manage.py 文件同级目录下运行 python,或者该目录是包含于 Python path 中,不然的话 import mysite 将不会正常运行。

更多内容请看 django-admin 文档

在shell命令行下,就可以开始探索 数据库 API:

# 导出我们之前创建的模型类
>>> from polls.models import Question, Choice

# 目前系统还没有任何数据
>>> Question.objects.all()
[]

# 创建一个新的 Question。
# 默认配置下"时区"是开启的
# Django是通过tzinfo来预测日期和时间的。使用timezone.now()
# 与datetime.datetime.now()的值相同
>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())

# 要保存该对象到数据库,须要明确调用函数 save()
>>> q.save()

# 现在该对象就有了一个 ID 号。注意该值可能显示为 "1L" 或者是 "1",这取决于你所使用的数据库,这并不重要,只是数据库后端中返回的整形值,对应为Python的长整型值。
>>> q.id
1

# 通过Python属性的方式来访问数据模型值。
>>> q.question_text
"What's new?"
>>> q.pub_date
datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>)

# 修改了变量的值后,需要调用函数 save()
>>> q.question_text = "What's up?"
>>> q.save()

# objects.all() 返回数据库所有 questions记录
>>> Question.objects.all()
[<Question: Question object>]

请稍等一下, <Question: Question object> 为对象返回的信息没有任何实际意义(相当于说“返回了一个对象”或者”存在一个对象“)。下面编辑该模型( polls/models.py 文件)为 QuestionChoice 都分别添加一个方法__str__()就可以修正该问题:

polls/models.py
from django.db import models

class Question(models.Model):
    # ...
    def __str__(self):              # Python 2的话是__unicode__()
        return self.question_text

class Choice(models.Model):
    # ...
    def __str__(self):              # Python 2的话是__unicode__()
        return self.choice_text

为模型添加 __str__() 方法很重要,不仅仅是在交互方式下为我们提供了方便,同样在Django自动生成的管理界面也会使用到。

__str__ or __unicode__?

在 Python 3,使用的是 __str__()

在 Python 2,应该使用的是 __unicode__() 方法,它返回的是 unicode 字符。Django模型有一个默认方法 __str__() 会调用 __unicode__() 并转换其值为UTF-8字符串 这就是说 unicode(p) 将返回一个 Unicode 字符串,而 str(p)``将返回 一个用UTF-8编码的字节串。Python则相反: ``object 对象有一个 __unicode__``方法,它会调用 ``__str__,将结果转换为一个ASCII 字节串。这个区别可能会带来混乱。

string, and str(p) will return a bytestring, with characters encoded as UTF-8. Python does the opposite: object has a __unicode__ method that calls __str__ and interprets the result as an ASCII bytestring. This difference can create confusion.

我们在本教程中的代码都是在Python 3版本。

上面仅仅是使用的 Python中的典型方法。 下面我们演示下怎么自定义方法:

polls/models.py
import datetime

from django.db import models
from django.utils import timezone


class Question(models.Model):
    # ...
    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

注意 import datetimefrom django.utils import timezone 这两个分别引用了 Python标准库中 datetime 模块和 Django时区工具 django.utils.timezone。如果你对Python时区模块方面不太熟悉,可以看看 时区支持文档

保存这些修改后,运行``python manage.py shell``重新开启一个交互模式的Python shell:

>>> from polls.models import Question, Choice

# 确定下刚才添加的 __str__() 方法能否正确运行
>>> Question.objects.all()
[<Question: What's up?>]

# Django 提供了一组丰富的数据查找 API,它们都有一个关键字参数
>>> Question.objects.filter(id=1)
[<Question: What's up?>]
>>> Question.objects.filter(question_text__startswith='What')
[<Question: What's up?>]

# 查找在今年发布的Question
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
<Question: What's up?>

# 如果某个请求 ID不存在,就会引发一个异常
>>> Question.objects.get(id=2)
Traceback (most recent call last):
    ...
DoesNotExist: Question matching query does not exist.

# 通过主键进行查找是非常常见的,所以Django提供了一个快捷方式
# 下面的方法与Question.objects.get(id=1)相同
>>> Question.objects.get(pk=1)
<Question: What's up?>

# 确定我们自定义的方法能正常工作
>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
True

# 给``问题``(Question)添加几个``选票``(Choices)
# 这里create()将构建一个新的Choice对象:执行插入语句,添加一个选票
# 到可用的选票集中,并返回这个新的选票对象。
# Django能为主键引用的另一个关联对象创建一组新对象
# (比如某个问题的选票)这些关联的对象也能通过API来访问
>>> q = Question.objects.get(pk=1)

# 显示一个被关联到某个对象的所有对象集-现在还是空的
>>> q.choice_set.all()
[]

# 新建3个选票``choice``
>>> q.choice_set.create(choice_text='Not much', votes=0)
<Choice: Not much>
>>> q.choice_set.create(choice_text='The sky', votes=0)
<Choice: The sky>
>>> c = q.choice_set.create(choice_text='Just hacking again', votes=0)

# 选票对象``Choice``能通过 API访问到它被关联到的对象``Question``
# (即这个``choice``属于哪个``Question``)
>>> c.question
<Question: What's up?>

# 关联对象和被关联对象之间可以相互引用
# 对象``Question``也能访问到它所关联的对象 Choice
# (即这个问题``Question``目前有哪些选票``Choice``)
>>> q.choice_set.all()
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
>>> q.choice_set.count()
3

#  API能够按照你的需求自动向下引用对象
# 使用双下划来创建对象的引用关系
# 这种引用在多个对象间的相互关联时也能正常运行,关联的层级没有限制
# 比如查找发布日期为今年的所有question对象,然后这些对象各自关联到的choice对象
# (重复使用了我们上面创建的变量 'current_year' ).
>>> Choice.objects.filter(question__pub_date__year=current_year)
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]

# 使用delete()来删除某个关联到的choices对象
>>> c = q.choice_set.filter(choice_text__startswith='Just hacking')
>>> c.delete()

关于模型引用的详细信息请看 引用访问对象。 如何在API中使用双下划线来进行字段查找请看 字段查找。 数据库API详情请看 数据库API文档

你对API能够运用自如时,请进入 教程第2部分 让Django自动管理界面运行起来。