Skip to content

简介

常用链接

https://github.com/django/django

https://www.djangoproject.com/

https://docs.djangoproject.com/zh-hans/2.2/

https://www.django-rest-framework.org/

https://github.com/encode/django-rest-framework/tree/master

https://github.com/the-benchmarker/web-frameworks

基本介绍

Django 是用 Python 开发的一个免费开源的 Web 框架,几乎囊括了 Web 应用的方方面面,可以用于快速搭建高性能、优雅的网站。

Django 提供了许多网站后台经常用到的模块,使开发者能够专注于业务部分。
Django 提供了通用 Web 开发模式的高度抽象,为频繁进行编程作业提供了快速解决方法,并为“如何解决问题”提供了清晰明了的约定。
Django 通过 DRY(Don't Repeat Yourself,不要重复自己)的理念来鼓励快速开发。

自带管理后台
只需几行简单代码的设置,就可以让目标网站拥有一个强大的管理后台,轻松对内容进行增加、删除、修改与查找,
并且能很方便地定制搜索、过滤等操作,因为特别适合用于内容管理平台。

灵活的路由系统
可以定义优雅的访问地址,按需定义,毫无障碍。

强大的数据库 ORM:
拥有强大的数据库操作接口(QuerySet API),可以轻松执行原声 SQL。

易用的模板系统:
自带强大、易扩展的模板系统。
当前后端分离开发时,可以只用 Django 开发 API,不使用模板系统,也可以轻易替换成其他模板。

缓存系统
与 Memcached,Redis 等缓存系统联合使用,获得更快的加载速度。

Django 发布情况

功能版本(A.B,A.B+1,如 2.0,2.1 等)大约每 8 个月发布一次。
这些版本将包含新功能以及对现有功能的改进等,也可能包含与上一个版本不兼容的功能,详细的说明在版本的发布日志(Release Notes)中可以查阅到。

补丁版本(A.B.C,如 2.1.3)会根据需要发布,以修复错误和安全问题。
这些版本将与相关的功能版本 100% 兼容,除非是出于安全原因或为了防止数据丢失而无法做到 100% 兼容。
因此,“我应该升级到最新的补丁版本么?”的答案永远都是“是的”。
如果之前使用的是 Django2.1,现在最新的版本是 Djabgo 2.1.3,那么可以放心将 2.1 版本升级到 2.1.3 版本。

某些功能版本被指定为长期支持(LTS)版本,这种稳定版本通常自发布之日起 3 年以内,会持续发布安全和关键补丁,即所谓提供持续稳定的支持。

在 Django 官网的下载页面的下载页面底部,有介绍各种版本的发布和支持生命周期,比较大的变化就是从 Django 2.0 开始,它不再支持 Python 2。

https://www.djangoproject.com/download/

如图 1-1 所示,可以看到 Django 各版本的发布情况和支持计划等。


图1-1 Django各版本的发布情况和支持计划

Django 的 MVT 架构简介

Django 是一个 Python Web 框架。和大多数框架一样,Django 支持 MVC 模式。
首先来看看什么是 MVC(Model-View-Controller)模式,然后了解 Django MVT(Model-View-Template)的不同之处。

MVC 模式

MVC(Model-View-Controller)模式是开发 Web 应用程序的一种软件设计模式,其中各部分功能如下:

模型(Model):
位于模式底层,负责管理应用程序的数据。它处理来自视图的请求,并且响应来自控制器的指令以更新自身。

视图(View):
负责向用户以特定格式呈现全部或部分数据。

控制器(Controller):
控制模型和视图之间交互的代码。

Django MVT 模式

MVT(Model-View-Template)与 MVC 略有不同。
主要区别在于 Django 本身已经实现了控制器(Controller)这部分的功能,暴露给开发者的是模板(Template)。
我们可以简单认为 Django 中的模板是 HTML 文件,但其支持 Django 的模板语言。
这种模板语言简单来说就是通过占位符、循环、逻辑判断等来控制页面上的内容展示,如图 1-2 所示。


图1-2 Django中的MVT模式

Django 和主流 Web 框架对比

用于 Python Web 开发的框架有很多,比如 Flask、Bottle、Pyramid、Webpy 等,这里主要将 Django 同 Flask 与 Tornado 框架分别对比一下。

Flask 是小而精的微框架(Micro Framework),它不像 Django 那样大而全。
如果使用 Flask 开发,开发者需要自己决定使用哪个数据库 ORM、模版系统、用户认证系统等,需要自己去组装这些系统。
与采用 Django 开发相比,开发者在项目开始的时候可能需要花更多的时间去了解、挑选各个组件,正因为这样,Flask 开发的灵活度更高,开发者可以根据自己的需要去选择合适的插件。
由于是自己一步步地将整个系统组装起来的,因为也比较容易了解各个组件部分。
当然,Flask 历史相对更短,第三方 App 自然没有 Django 那么全面。

Tornado 是一个 Python Web 框架和异步网络库,最初由 FriendFeed 开发。
当初设计它的目的是为了解决 10000 个并发连接(C10K 问题),传统的 Apache 服务器会为每个 HTTP 请求连接一个线程,而在大多数 Linux 发行版中默认线程堆(Heap)大小是 8MB,当连接数量过多时,这种线程池的方式极易耗光服务器上的所有资源。
Tornado 会把等待资源的操作挂起,当数据准备好时,再回调相应的函数。
通过使用非阻塞网络 I/O,Tornado 可以轻松应对数万个连接。
因而 Tornado 也就成为长轮询,是 WebSocket 和其他需要与每个用户建立长期连接的应用程序的理想选择。
和 Django 相比,使用 Tornado 编写异步代码对于开发者来说,没有 Django 或 Flask 编写同步代码那么简单、直接和高效。

安装

pip install Django==2.2

1
2
➜  ~ python -m django --version
2.2
1
2
In [2]: django.get_version()
Out[2]: '2.2'

初识 Django

Django 最初被设计用于具有快速开发需求的新闻类站点,目的是要实现简单快捷的网站开发。
以下内容简要介绍了如何使用 Django 实现一个数据库驱动的 Web 应用。

设计模型

Django 无需数据库就可以使用,它提供了 对象关系映射器 通过此技术,你可以使用 Python 代码来描述数据库结构。

你可以使用强大的 数据-模型语句 来描述你的数据模型,这解决了数年以来在数据库模式中的难题。以下是一个简明的例子:

mysite/news/models.py:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
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命令行实用程序以自动创建数据库表:

1
2
$ python manage.py makemigrations
$ python manage.py migrate

该 makemigrations 命令查找所有可用的models,为任意一个在数据库中不存在对应数据表的model创建 migrations 脚本文件。migrate 命令则运行这些 migrations 自动创建数据库表

享用便捷的 API

接下来,你就可以使用一套便捷而丰富的 Python API 访问你的数据。这些 API 是即时创建的,而不用显式的生成代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# Import the models we created from our "news" app
>>> from news.models import Article, Reporter

# No reporters are in the system yet.
>>> Reporter.objects.all()
<QuerySet []>

# Create a new Reporter.
>>> r = Reporter(full_name='John Smith')

# Save the object into the database. You have to call save() explicitly.
>>> r.save()

# Now it has an ID.
>>> r.id
1

# Now the new reporter is in the database.
>>> Reporter.objects.all()
<QuerySet [<Reporter: John Smith>]>

# Fields are represented as attributes on the Python object.
>>> r.full_name
'John Smith'

# Django provides a rich database lookup 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.

# Create an article.
>>> from datetime import date
>>> a = Article(pub_date=date.today(), headline='Django is cool',
...     content='Yeah.', reporter=r)
>>> a.save()

# Now the article is in the database.
>>> Article.objects.all()
<QuerySet [<Article: Django is cool>]>

# Article objects get API access to related Reporter objects.
>>> r = a.reporter
>>> r.full_name
'John Smith'

# And vice versa: Reporter objects get API access to Article objects.
>>> r.article_set.all()
<QuerySet [<Article: Django is cool>]>

# The API follows relationships as far as you need, performing efficient
# JOINs for you behind the scenes.
# This finds all articles by a reporter whose name starts with "John".
>>> Article.objects.filter(reporter__full_name__startswith='John')
<QuerySet [<Article: Django is cool>]>

# Change an object by altering its attributes and calling save().
>>> r.full_name = 'Billy Goat'
>>> r.save()

# Delete an object with delete().
>>> r.delete()

一个动态管理接口:并非徒有其表

当你的模型完成定义,Django 就会自动生成一个专业的生产级 管理接口 ——一个允许认证用户添加、更改和删除对象的 Web 站点。
你只需简单的在 admin 站点上注册你的模型即可:

mysite/news/models.py:

1
2
3
4
5
6
7
from django.db import models

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)

mysite/news/admin.py:

1
2
3
4
5
from django.contrib import admin

from . import models

admin.site.register(models.Article)

这样设计所遵循的理念是,站点编辑人员可以是你的员工、你的客户、或者就是你自己——而你大概不会乐意去废半天劲创建一个只有内容管理功能的后台管理界面。

创建 Django 应用的典型流程是,先建立数据模型,然后搭建管理站点,之后你的员工(或者客户)就可以向网站里填充数据了。
后面我们会谈到如何展示这些数据。

规划 URLs

简洁优雅的 URL 规划对于一个高质量 Web 应用来说至关重要。
Django 推崇优美的 URL 设计,所以不要把诸如 .php 和 .asp 之类的冗余的后缀放到 URL 里。

为了设计你自己的 URLconf,你需要创建一个叫做 URLconf 的 Python 模块。
这是网站的目录,它包含了一张 URL 和 Python 回调函数之间的映射表。
URLconf 也有利于将 Python 代码与 URL 进行解耦(译注:使各个模块分离,独立)。

下面这个 URLconf 适用于前面 Reporter/Article 的例子:

mysite/news/urls.py:

1
2
3
4
5
6
7
8
9
from django.urls import path

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:

1
2
3
4
5
6
7
8
from django.shortcuts import render

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)

这个例子使用了 Django 模板系统 ,它有着很多强大的功能,而且使用起来足够简单,即使不是程序员也可轻松使用。

设计模板

上面的代码加载了 news/year_archive.html 模板。

Django 允许设置搜索模板路径,这样可以最小化模板之间的冗余。
在 Django 设置中,你可以通过 DIRS 参数指定一个路径列表用于检索模板。
如果第一个路径中不包含任何模板,就继续检查第二个,以此类推。

让我们假设 news/year_archive.html 模板已经找到。它看起来可能是下面这个样子:

mysite/news/templates/news/year_archive.html:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
{% 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 风格的“管道符”(“|”字符)。
这是一个模板过滤器,用于过滤变量值。
在这里过滤器将一个 Python datetime 对象转化为指定的格式(就像 PHP 中的日期函数那样)。

你可以将多个过滤器连在一起使用。你还可以使用你 自定义的模板过滤器 。
你甚至可以自己编写 自定义的模板标签 ,相关的 Python 代码会在使用标签时在后台运行。

Django 使用了 ''模板继承'' 的概念。这就是 {% extends "base.html" %} 的作用。
它的含义是''先加载名为 base 的模板,并且用下面的标记块对模板中定义的标记块进行填充''。
简而言之,模板继承可以使模板间的冗余内容最小化:每个模板只需包含与其它文档有区别的内容。

下面是 base.html 可能的样子,它使用了 静态文件 :

mysite/templates/base.html:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{% 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),并且给子模板们挖好了可以填的”坑“。
这也让网站的改版变得简单无比——你只需更改这个根模板文件即可。

它还可以让你利用不同的基础模板并重用子模板创建一个网站的多个版本。
Django 的创建者已经利用这一技术来创造了明显不同的手机版本的网站——只需创建一个新的基础模板。

注意,你并不是非得使用 Django 的模板系统,你可以使用其它你喜欢的模板系统。
尽管 Django 的模板系统与其模型层能够集成得很好,但这不意味着你必须使用它。
同样,你可以不使用 Django 的数据库 API。
你可以用其他的数据库抽象层,像是直接读取 XML 文件,亦或直接读取磁盘文件,你可以使用任何方式。
Django 的任何组成——模型、视图和模板——都是独立的。