Django 最初被设计用于具有快速开发需求的新闻类站点,目的是要实现简单快捷的网站开发。下面简要介绍如何使用 Django 实现一个数据库驱动的 Web 应用。
Django 无需数据库就可以使用,它提供了对象关系映射器(Object–relational mapping) 通过此技术,你可以使用 Python 代码来描述数据库结构。
可以使用强大的 数据-模型语句 来描述你的数据模型:
# mysite/news/models.py
from django.db import models
class Reporter(models.Model):
full_name = models.CharField(max_length=70)
def __str__(self):
return self.full_name
class Article(models.Model):
pub_date = models.DateField()
headline = models.CharField(max_length=200)
content = models.TextField()
reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE)
def __str__(self):
return self.headline
运行Django命令行实用程序以自动创建数据库表:
# linux/mac
$ python manage.py makemigrations
$ python manage.py migrate
# windows
...\> py manage.py makemigrations
...\> py manage.py migrate
makemigrations 命令查找所有可用的模型,为任意一个在数据库中不存在对应数据表的模型创建迁移脚本文件。migrate 命令则运行这些迁移来自动创建数据库表。
# 从“新闻”应用程序导入创建的模型
>>> from news.models import Article, Reporter
# 系统中还没有记者.
>>> Reporter.objects.all()
<QuerySet []>
# 增加一个新的记者
>>> r = Reporter(full_name='John Smith')
# 将对象保存到数据库. 必须明确地调用save().
>>> r.save()
# 现在有一个ID.
>>> r.id
1
# 现在新的记者在数据库中了.
>>> Reporter.objects.all()
<QuerySet [<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.
# 创建一篇文章.
>>> from datetime import date
>>> a = Article(pub_date=date.today(), headline='Django is cool',
... content='Yeah.', reporter=r)
>>> a.save()
# 现在该文章在数据库中了.
>>> Article.objects.all()
<QuerySet [<Article: Django is cool>]>
# 文章对象可通过API访问相关的Reporter对象.
>>> r = a.reporter
>>> r.full_name
'John Smith'
# 反之亦然:Reporter对象获得对Article对象的API访问权限.
>>> r.article_set.all()
<QuerySet [<Article: Django is cool>]>
# API会按照你需要的关系进行跟踪,从而有效地执行
# 在幕后加入.
# 将查找记者姓名以“ John”开头的所有文章.
>>> Article.objects.filter(reporter__full_name__startswith='John')
<QuerySet [<Article: Django is cool>]>
# 通过更改对象的属性并调用save()来更改对象.
>>> r.full_name = 'Billy Goat'
>>> r.save()
# 使用delete()删除对象.
>>> r.delete()
当你的模型完成定义,Django 就会自动生成一个专业的生产级**管理接口 ** —— 一个允许认证用户添加、更改和删除对象的 Web 站点,只需在管理站点上注册你的模型即可:
# mysite/news/admin.py
from django.contrib import admin
from . import models
admin.site.register(models.Article)
创建 Django 应用的典型流程是:
先建立数据模型,然后搭建管理站点,之后你的员工(或者客户)就可以向网站里填充数据了。
简洁优雅的 URL 规划对于一个高质量 Web 应用来说至关重要。Django 推崇优美的 URL 设计,所以不要把诸如 .php
和 .asp
之类的冗余的后缀放到 URL 里。
为了设计你自己的 URLconf ,你需要创建一个叫做 URLconf 的 Python 模块。这是网站的目录,它包含了一张 URL 和 Python 回调函数之间的映射表。URLconf 也有利于将 Python 代码与 URL 进行解耦(译注:使各个模块分离,独立)。
下面这个 URLconf 适用于前面 Reporter
/Article
的例子:
# mysite/news/urls.py
from . import views
urlpatterns = [
path('articles/<int:year>/', views.year_archive),
path('articles/<int:year>/<int:month>/', views.month_archive),
path('articles/<int:year>/<int:month>/<int:pk>/', views.article_detail),
]
上述代码将 URL 路径映射到了 Python 回调函数(“视图”)。路径字符串使用参数标签从URL中“捕获”相应值。当用户请求页面时,Django 依次遍历路径,直至初次匹配到了请求的 URL。(如果无匹配项,Django 会调用 404 视图。) 这个过程非常快,因为路径在加载时就编译成了正则表达式。
一旦有 URL 路径匹配成功,Django 会调用相应的视图函数。每个视图函数会接受一个请求对象 —— 包含请求元信息 —— 以及在匹配式中获取的参数值。
例如,当用户请求了这样的 URL “/articles/2005/05/39323/”,Django 会调用 news.views.article_detail(request, year=2005, month=5, pk=39323)
。
视图函数的执行结果只可能有两种:返回一个包含请求页面元素的 HttpResponse
对象,或者是抛出 Http404
这类异常,执行过程中的其它的动作则由自己决定。
通常来说,一个视图的工作就是:从参数获取数据,装载一个模板,然后将根据获取的数据对模板进行渲染。下面是一个 year_archive
的视图样例:
# mysite/news/views.py
from .models import Article
def year_archive(request, year):
a_list = Article.objects.filter(pub_date_year=year)
context = {'year':year, 'article_list':a_list}
return render(request, 'news/year_archive.html', context)
上面的代码加载了 news/year_archive.html
模板。
Django 允许设置搜索模板路径,这样可以最小化模板之间的冗余。在 Django 设置中,你可以通过 DIRS 参数指定一个路径列表用于检索模板。如果第一个路径中不包含任何模板,就继续检查第二个,以此类推。
假设 news/year_archive.html
已有模板
# mysite/news/templates/news/year_archive.html
{% extends "base.html" %}
{% block title %}Articles for {{year}}{% endblock %}
{% block content %}
<h1>Article 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 风格的“管道符”(“|”字符)。这是一个模板过滤器,用于过滤变量值。在这里过滤器将一个 Python datetime 对象转化为指定的格式。
Django 使用了 ‘‘模板继承’’ 的概念,就是 {% extends "base.html" %}
的作用。它的含义是’‘先加载名为 base 的模板,并且用下面的标记块对模板中定义的标记块进行填充’’。简而言之,模板继承可以使模板间的冗余内容最小化:每个模板只需包含与其它文档有区别的内容。
<-->mysite/templates/base.html</-->
{% load static %}
<html>
<head>
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<img src="{% static 'images/sitelogo.png' %}" alt="Logo">
{% block content %}{% endblock %}
</body>
</html>
简而言之,它定义了这个网站的外观(利用网站的 logo),并且给子模板们挖好了可以填的”坑“。这就意味着你可以通过修改基础模板以达到重新设计网页的目的。它还可以让你利用不同的基础模板并重用子模板创建一个网站的多个版本。