因为 Django 是在一个快节奏的新闻编辑部中开发出来的,它被设计用来让普通的网站开发工作简单快 捷。以下是一个教你使用 Django 创建一个数据库驱动的网站应用的大纲。
这个文档的目标是让你有足够的技巧和能力了解 Django 是如何工作的,但是它并不是表示它是一个新 手指南或者参考目录 – 其实这些我们都有!当你准备好新建一个项目,你可以 从新手指南开始 或者 深入阅读详细的文档.
尽管你在 Django 中可以不使用数据库,但是它提供了一个完善的可以用 Python 代码描述你的数据库 结构的对象关联映射(ORM)。
model 语法 提供了丰富的表现你的 models 的方法 – 目前为止,它解 决了不少关于数据库模式的问题。the file这里是一个简单的例子,一般保存在一个名为 mysite/news/models.py 的文件中:
class Reporter(models.Model):
full_name = models.CharField(max_length=70)
def __unicode__(self):
return self.full_name
class Article(models.Model):
pub_date = models.DateTimeField()
headline = models.CharField(max_length=200)
content = models.TextField()
reporter = models.ForeignKey(Reporter)
def __unicode__(self):
return self.headline
通过它,你可以使用一个方便功能丰富的 Python API 来访问你的数据。 API 是动态生成的,不需要生成代码:
# 导入我们在 "news" app 中创建的 models
>>> from news.models import Reporter, Article
# 在系统中目前还没有 reporters
>>> Reporter.objects.all()
[]
# 创建一个新的 Reporter
>>> r = Reporter(full_name='John Smith')
# 将对象保存到数据库。你需要显示的调用 save() 方法。
>>> r.save()
# 现在它有一个 ID 了。
>>> r.id
1
# 现在新的 reporter 已经在数据库里面了。
>>> Reporter.objects.all()
[<Reporter: John Smith>]
# 字段被表示为一个 Python 对象的属性。
>>> r.full_name
'John Smith'
# Django 提供了丰富的数据库查询 API。
>>> Reporter.objects.get(id=1)
<Reporter: John Smith>
>>> Reporter.objects.get(full_name__startswith='John')
<Reporter: John Smith>
>>> Reporter.objects.get(full_name__contains='mith')
<Reporter: John Smith>
>>> Reporter.objects.get(id=2)
Traceback (most recent call last):
...
DoesNotExist: Reporter matching query does not exist.
# 创建一个 article
>>> from datetime import datetime
>>> a = Article(pub_date=datetime.now(), headline='Django is cool',
... content='Yeah.', reporter=r)
>>> a.save()
# 现在 article 已经在数据库中了。
>>> Article.objects.all()
[<Article: Django is cool>]
# Article 对象有 API 可以访问到关联到 Reporter 对象。
>>> r = a.reporter
>>> r.full_name
'John Smith'
# 反之亦然:Reporter 对象也有访问 Article 对象的API。
>>> r.article_set.all()
[<Article: Django is cool>]
# API 会在后台有效的联合表,以便满足你的关联查询的要求。
# 以下这个例子会找出 名字以 "John" 开头的 reporter 的所有的 articles。
>>> Article.objects.filter(reporter__full_name__startswith="John")
[<Article: Django is cool>]
# 通过更改一个对象的属性,然后调用 save() 方法来改变一个对象的值。
>>> r.full_name = 'Billy Goat'
>>> r.save()
# 使用 delete() 方法删除一个对象。
>>> r.delete()
一旦你的 models 被定义好,Django 能自动创建一个专业的,可以用于生产环境 的 管理界面 – 一个让满足权限的用户增 加删除修改数据对象的网站。它使用起来也非常简单只需要在你的 admin site 中注册你的 model 即可:
# In models.py...
from django.db import models
class Article(models.Model):
pub_date = models.DateTimeField()
headline = models.CharField(max_length=200)
content = models.TextField()
reporter = models.ForeignKey(Reporter)
# In admin.py in the same directory...
import models
from django.contrib import admin
admin.site.register(models.Article)
这种设计的哲学是你的网站一般会由一个员工或者客户编辑,或者仅仅是你自己 – 而你应该不会想要仅仅为了管理内容而去创建后台界面。
在一个创建 Django 应用的典型工作流中,首先需要创建 models 并尽快让 admin sites 工作起来,这样你的员工(或者客户)能够开始录入数据。然后,开 发数据被展示给公众的方法。
一个干净的,优雅的 URL 方案是一个高质量 Web 应用程序的重要细节。Django 鼓励使用漂亮的 URL设计,并且不鼓励把没必要的东西放到 URLs 里面,像是 .php 或 .asp 。
为了给一个 app 设计 URLs,你需要创建一个 Python 模块叫做 URLconf 。一个你的 app 内容的目录,他包含一个简单的 URL 模 式与 Python 回调函数的映射关系。同时这有助于解耦 Python 代码和 URLs 。
这里是一个 URLconf 看起来的样子,针对上面的 Reporter / Article 例子:
from django.conf.urls import patterns, url, include
urlpatterns = patterns('',
(r'^articles/(\d{4})/$', 'news.views.year_archive'),
(r'^articles/(\d{4})/(\d{2})/$', 'news.views.month_archive'),
(r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'news.views.article_detail'),
)
上面的代码映射了 URLs,从一个简单的正则表达式,到 Python 回调函数的位置 (“views”)。正则表达式使用圆括号”捕获” URLs 的值。当用户请求一个页面时, Django 通过按照顺序的匹配每一个模式,并停在第一个匹配请求的 URL 上。(如 果没有匹配到, Django 将会展示一个404错误页面。)整个过程是极快的,应为 在加载时正则表达式就进行了编译。
一旦有一个正则表达式匹配上了,Django 将导入然后调用后面的视图中的函数, 它其实就是调用了一个简单的 Python 函数。每个视图将得到一个 request 对象 – 它包含了 request 的 meta 信息(metadata) – 和通过正则被捕获到的值。
例如,如果一个用户请求了这个 URL “/articles/2005/05/39323/” , Django会 这样调用函数 news.views.article_detail(request, '2005', '05', '39323') 。
每个视图都只做两件中一件事情:要么返回一个包含请求结果的页面的 HttpResponse 对象,要么抛出一个异常,如 Http404 。至于其他就看你自己了。
通常来说,一个view视图会根据参数接受数据,加载模板,使用提供的数据渲染 模板。下面是一个 按年归档 的例子:
def year_archive(request, year):
a_list = Article.objects.filter(pub_date__year=year)
return render_to_response('news/year_archive.html', {'year': year, 'article_list': a_list})
这个例子使用了 Django 的 模板系统 。模板系统 功能强大, 但是简单易用,甚至不会编程的人也会使用。
上面的例子中载入了 news/year_archive.html 模板。
Django 有一个模板搜索路径,他让你能够尽可能的重复使用模板。在你的 Django设置中,你可以指定一个查找模板的目录列表。如果一个模板没有在这个 列表中的地一个文件夹中找到,那么它会去找下一个,然后以此类推。
假设我们已经找到了 news/article_detail.html 模板,模板内容大概会是这样:
{% extends "base.html" %}
{% block title %}Articles for {{ year }}{% endblock %}
{% block content %}
<h1>Articles for {{ year }}</h1>
{% for article in article_list %}
<p>{{ article.headline }}</p>
<p>By {{ article.reporter.full_name }}</p>
<p>Published {{ article.pub_date|date:"F j, Y" }}</p>
{% endfor %}
{% endblock %}
模板中的变量都使用双花括号包围。 {{ article.headline }} 表示 “输出 article 的headline 属性”。但是点符号不仅用于表示属性,还用于表示字典的 键值查找、索引查找和函数调用。
注意, {{ article.pub_date|date:"F j, Y" }} 中使用了 Unix类系统 中 的“管道”( Unix 中用“ | ”符号表示管道)。这里被称为模板过滤器。这是 一种过滤变量的方式。 本例中, Python 的日期时间对象被过滤成了指定的格式。 (在 PHP 的日期函数中可以见到这种变换;是的,PHP也是有优秀之处的)。
你可以无限制地串联使用多种过滤器,还可以定制自己的过滤器。你可以定制自 己的模板标记,在后台执行自定义的 Python 代码。
最后,Django 使用了 “模板继承” 的概念。这是 {% extends "base.html" %} 所做的事情。他意味着 “首先载入名为‘base’的模板的内容到当前模板, 然后再处理本模板中的其余内容。”简而言之,模板继承可以使用模板显著地缩 短合并模板中相同的部分:每一个模板只需要定义它独特的部分即可。
下面是 “base.html” 模板看起来的样子:
<html>
<head>
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<img src="sitelogo.gif" alt="Logo" />
{% block content %}{% endblock %}
</body>
</html>
模板内容相当清晰。例子模板定义了整个站点的外观(包括站点的 logo ),并 留下了一个“洞”,等待子模板来填充。这种做法使站点的重新设计变得非常方 便 – 只要改动 base.html 这一个文件就可以了。
这种做法还有一个好处:可以保持子模板不变,而方便地创建不同版本的站点。 Django 的创建者已经使用这项技术创建了因手机号码不同而产生的不同版本站点, 而所做的工作只是创建新的基础模板而已。
注意,如果你喜欢其他模板系统,那么你不必一定要使用 Django 的模板系统。 虽然 Django 的模板系统非常适合 Django 的模型,但这不是必须的。同理,你 也不必强迫 使用 Django 的数据库 API 。你可以使用其他数据库抽象工具、可 以读取 XML 文件、 可以读取磁盘上的文件或者其他任何方法来操作数据库。 Django 的每个组成部分: 模型、视图和模板都可以解耦,以后会谈到。
Dec 14, 2013