Django Web 开发学习手册(三)

原文:zh.annas-archive.org/md5/C7E16835D8AC71A567CF7E772213E9F7

译者:飞龙

协议:CC BY-NC-SA 4.0

第十章:扩展 Django

到目前为止,我们已经走了很长的路,涉及了大量与 Django 功能相关的代码和基本概念。在本章中,我们将更多地讨论 Django,但我们将简要讨论不同的参数,例如自定义标签、过滤器、子框架、消息系统等。以下是本章将涉及的主题:

  • 自定义模板标签和过滤器

  • 基于类的通用视图

  • 贡献的子框架

  • 消息系统

  • 订阅系统

  • 用户分数

自定义模板标签和过滤器

Django 模板系统配备了许多模板标签和过滤器,使编写模板变得简单灵活。但是,有时您可能希望使用自己的标签和过滤器扩展模板系统。当您发现自己多次重复相同的标签结构时,希望将结构包装在单个标签中,甚至希望添加到模板系统中的过滤器时,通常会发生这种情况。

猜猜?Django 已经允许您这样做,而且这也很容易!您基本上只需向应用程序添加一个名为templatetags的新包,并将包含标签和过滤器的模块放入其中。让我们通过添加一个将字符串大写的过滤器来学习这一点。在mytweets父文件夹中添加一个templatetags文件夹,并在其中放置一个名为__init__.py的空文件,以便 Python 将该文件夹视为包。现在,在其中创建一个名为mytweet_filters的模块。我们将在此模块中编写我们的过滤器。以下是目录结构的示例:

templatetags/
  |-- __init__.py
  -- mytweet_filters.py

现在,将以下代码添加到mytweet_filters.py文件中:

  from django import template
  register = template.Library()

  @register.filter
  def capitalize(value):
    return value.capitalize()

register变量是一个对象,可用于向模板系统引入新的标签和过滤器。在这里,我们使用register.filter装饰器将 capitalize 函数添加为过滤器。

要在模板中使用新的过滤器,请在模板文件的开头放入以下行:

{% load mytweet_filters %}

然后,您可以像使用 Django 提供的任何其他过滤器一样使用新的过滤器:

Hi {{ name|capitalize }}!

添加自定义模板标签的工作方式与过滤器类似。基本上,您定义方法来处理标签,然后注册标签以使其可用于模板。这个过程稍微复杂一些,因为标签可能比过滤器更复杂。有关自定义模板标签的更多信息,请参阅 Django 在线文档。

在编写自定义过滤器时,您必须注意 Django 的自动转义行为。可以传递给过滤器的字符串有三种类型:

  • 原始字符串:此字符串是通过str命令准备的,或者是用 unicode 形成的。如果启用了自动转义,它们将自动转义。

  • 安全字符串:这些字符串是标记为免受进一步转义的字符串。它们不需要进一步转义。要将输出标记为安全字符串,请使用django.utils.safestring.mark_safe()模块。

  • 标记为“需要转义”的字符串:顾名思义,它们始终需要转义。

基于类的通用视图

在使用 Django 时,您会注意到无论您正在处理哪个项目,总是需要某些类型的视图。因此,Django 配备了一组可在任何项目中使用的视图。这些视图称为通用视图

Django 为以下目的提供了通用视图:

  • 为任务创建简单的视图,例如重定向到另一个 URL 或呈现模板

  • 列出和形成详细视图以显示数据模型中的对象-这些视图类似于管理页面显示数据模型的列表和详细页面

  • 生成基于日期的存档页面;这对博客特别有用

  • 创建,编辑和删除数据模型中的对象

Django 的基于类的视图可以通过定义子类或直接在 URL 配置中传递参数来配置。

子类充满了消除重写常见情况模板的约定。当您使用子类时,实际上可以通过提供新值来覆盖主类的属性或方法:

# app_name/views.py
from django.views.generic import TemplateView

class ContactView(TemplateView):
  template_name = "contact.html"

我们还将在urls.py文件中添加其条目以进行重定向:

# project/urls.py
from django.conf.urls.defaults import *
from some_app.views import ContactView

urlpatterns = patterns('',
  (r'^connect/', ContactView.as_view()),
)

有趣的是,我们可以通过文件更改来实现相同的效果,并且只需在urls.py文件中添加以下内容即可:

from django.conf.urls.defaults import *
from django.views.generic import TemplateView

urlpatterns = patterns('',
  (r'^contact/', TemplateView.as_view(template_name="contact.html")),
)

贡献的子框架

django.contrib包含 Django 的标准库。我们在本书的前几章中使用了该软件包中的以下子框架:

  • admin: 这是 Django 管理界面

  • auth: 这是用户认证系统

  • sessions: 这是 Django 会话框架

  • syndication: 这是提要生成框架

这些子框架极大地简化了我们的工作,无论我们是创建注册和认证功能,构建管理页面,还是为我们的内容提供提要。django.contrib包是 Django 的一个非常重要的部分。了解其子包及如何使用它们将为您节省大量时间和精力。

本节将为您提供有关此软件包中其他框架的简要介绍。您不会深入了解如何使用每个框架,但您将学到足够的知识以了解何时使用框架。一旦您想在项目中使用框架,您可以阅读在线文档以了解更多信息。

Flatpages

Web 应用程序可能包含静态页面。例如,您的网站可能包括一组很少更改的帮助页面。Django 提供了一个名为flatpages的应用程序来提供静态页面。该应用程序非常简单;它为您提供了一个数据模型,用于存储有关每个页面的各种信息,包括以下内容:

  • URL

  • 标题

  • 内容

  • 模板名称

  • 查看页面是否需要注册

要使用该应用程序,您只需在settings.py文件中的INSTALLED_APPS变量中启用它,并将其中间件添加到MIDDLEWARE_CLASSES变量中。之后,您可以使用 flatpages 应用程序提供的数据模型存储和管理静态页面。

人性化

humanize应用程序提供了一组过滤器,以为您的页面增添人性化的触感。

以下是可用过滤器的列表:

  • apnumber: 对于 1-9 的数字,它返回拼写的数字。否则,它返回数字。换句话说,1 变成’one’,9 变成’nine’,以此类推,而 10 保持为 10。

  • intcomma: 这接受一个整数并将其转换为带有逗号的字符串,例如:

4500 becomes 4,500.
45000 becomes 45,000.
450000 becomes 450,000.
4500000 becomes 4,500,000.
  • intword: 这将整数转换为易于阅读的形式,例如:

1000000 变成 1.0 百万。

1200000 becomes 1.2 million.
1200000000 becomes 1.2 billion.
  • naturalday: 基于日期所在的范围,如果给定日期在*(+1,0,-1)*范围内,则分别显示日期为"明天",“今天"和"昨天”,例如,(如果今天是 2007 年 1 月 26 日):
25 Jan 2007 becomes yesterday.
26 Jan 2007 becomes today.
27 Jan 2007 becomes tomorrow.
  • naturaltime: 这返回一个表示事件日期发生多少秒、分钟或小时前的字符串,例如,(如果现在是 2007 年 1 月 26 日 16:30:00):
26 Jan 2007 16:30:00 becomes now.
26 Jan 2007 16:29:31 becomes 29 seconds ago.
26 Jan 2007 16:29:00 becomes a minute ago.
26 Jan 2007 16:25:35 becomes 4 minutes ago.
26 Jan 2007 15:30:29 becomes 59 minutes ago.
26 Jan 2007 15:30:01 becomes 59 minutes ago.
26 Jan 2007 15:30:00 becomes an hour ago.
26 Jan 2007 13:31:29 becomes 2 hours ago.
25 Jan 2007 13:31:29 becomes 1 day, 2 hours ago.
25 Jan 2007 13:30:01 becomes 1 day, 2 hours ago.
25 Jan 2007 13:30:00 becomes 1 day, 3 hours ago.
26 Jan 2007 16:30:30 becomes 30 seconds from now.
26 Jan 2007 16:30:29 becomes 29 seconds from now.
26 Jan 2007 16:31:00 becomes a minute from now.
26 Jan 2007 16:34:35 becomes 4 minutes from now.
26 Jan 2007 17:30:29 becomes an hour from now.
26 Jan 2007 18:31:29 becomes 2 hours from now.
27 Jan 2007 16:31:29 becomes 1 day from now.
  • ordinal: 这将整数转换为序数形式。例如,1 变成’1st’,以此类推,每三个数字之间。

Sitemap

Sitemap是一个生成站点地图的框架,这些站点地图是帮助搜索引擎索引器在您的站点上找到动态页面的 XML 文件。它告诉索引器页面的重要性以及更改频率。这些信息使索引过程更准确和高效。

站点地图框架允许您用 Python 代码表示上述信息,然后生成代表您网站站点地图的 XML 文档。这涵盖了django.contrib包中最常用的子框架。该包包含一些不像前面那些重要的附加应用程序,并且会不时地更新新的应用程序。要了解django.contrib包中的任何应用程序,您可以随时阅读其在线文档。

跨站点请求伪造保护

我们在第五章中讨论了如何防止两种类型的 Web 攻击,即 SQL 注入和跨站点脚本。Django 提供了对抗另一种称为跨站点请求伪造的攻击的保护。在这种攻击中,恶意站点试图通过欺骗在您网站上登录的用户来操纵您的应用程序,使其打开一个特制的页面。该页面通常包含 JavaScript 代码,试图向您的网站提交表单。CSRF 保护通过将一个令牌(即秘密代码)嵌入到所有表单中,并在提交表单时验证该令牌来工作。这有效地使 CSRF 攻击变得不可行。

要激活 CSRF 保护,您只需要将'django.contrib.csrf.middleware.CsrfMiddleware'参数添加到MIDDLEWARE_CLASSES变量中,这将透明地工作,以防止 CSRF 攻击。

消息系统

我们的应用允许用户将彼此添加为好友并监视好友的书签。虽然这两种形式的通信与我们的书签应用程序的性质有关,但有时用户希望灵活地向彼此发送私人消息。这个功能对于增强我们网站的社交方面特别有用。

消息系统可以以多种方式实现。它可以简单到为每个用户提供一个联系表单,当提交时,通过发送其内容到用户的电子邮件来工作。您已经拥有构建此功能组件所需的所有信息:

  • 一个消息表单,其中包含主题的文本字段和消息正文的文本区域

  • 显示用户消息表单的视图,并通过send_mail()函数将表单内容发送给用户

当允许用户通过您的网站发送电子邮件时,您需要小心以防止滥用该功能。在这里,您可以将联系表单限制为仅限已登录的用户或仅限好友。

实现消息系统的另一种方法是在数据库中存储和管理消息。这样,用户可以使用我们的应用程序发送和查看消息,而不是使用电子邮件。虽然这种方法更加与我们的应用程序绑定,因此可以使用户留在我们的网站上,但需要更多的工作来实现。然而,与之前的方法一样,您已经拥有实现这种方法所需的所有信息。这里需要的组件如下:

  • 存储消息的数据模型。它应该包含发送者、接收者、主题和正文的字段。您还可以添加日期、阅读状态等字段。

  • 创建消息的表单。需要主题和正文的字段。

  • 列出可用消息的视图。

  • 显示消息的视图。

上述列表只是实现消息系统的一种方式。例如,您可以将列表和消息视图合并为一个视图,或者提供一个视图来显示已发送的消息以及已接收的消息。可能性很多,取决于您希望该功能有多高级。

订阅系统

我们提供了几种 Web 订阅,使用户能够监视我们网站的更新。然而,一些用户可能仍然更喜欢通过电子邮件监视更新的旧方式。对于这些用户,您可能希望将电子邮件订阅系统实施到应用程序中。例如,您可以让用户在朋友发布书签时收到通知,或者在特定标签下发布书签时收到通知。

此外,您可以将这些通知分组并批量发送,以避免发送大量的电子邮件。此功能的实现细节在很大程度上取决于您希望它如何工作。它可以是一个简单的数据模型,用于存储每个用户订阅的标签。它将循环遍历所有订阅特定标签的用户,并在此标签下发布书签时向他们发送通知。然而,这种方法太基础,会产生大量的电子邮件。更复杂的方法可能涉及将通知存储在数据模型中,并在每天发送一封电子邮件。

用户评分

一些网站(如Slashdot.orgreddit.com)通过为每个用户分配一个分数来跟踪用户的活动。每当用户以某种方式为网站做出贡献时,该分数就会增加。用户的分数可以以各种方式利用。例如,您可以首先向最活跃的用户发布新功能,或者为活跃用户提供其他优势,这将激励其他用户更多地为您的网站做出贡献。

实施用户评分非常简单。您需要一个数据模型来在数据库中维护评分。之后,您可以使用 Django 模型 API 从视图中访问和操作评分。

总结

本章的目的是为您准备本书未涵盖的任务。它向您介绍了许多主题。当需要某种功能时,您现在知道在哪里寻找框架,以帮助您快速而干净地实施该功能。

本章还为您提供了一些想法,您可能希望将其实施到我们的书签应用程序中。致力于这些功能将为您提供更多的机会来尝试 Django 并扩展您对其框架和内部工作原理的了解。

在下一章中,我们将介绍各种数据库连接的方式,如 MySQL、NoSQL、PostgreSQL 等,这对于任何基于数据库的应用程序都是必需的。

第十一章:数据库连接

Django 是一个数据库无关的框架,这意味着 Django 提供的数据库字段被设计为在不同的数据库中工作,比如 SQLite、Oracle、MySQL 和 PostgreSQL。事实上,它们也可以在几个第三方数据库后端上工作。PostgreSQL 是 Django 在生产中的一个很好的数据库,而 SQLite 用于开发环境,如果你不想为项目使用关系数据库管理系统(RDBMS),你将需要做很多工作。本章将详细介绍这两种类型的区别,并向您展示哪种更适合 Django,以及我们如何在 Django 项目中实际实现它们。

以下是本章将涉及的主题:

  • SQL 与 NoSQL

  • Django 与关系数据库

  • Django 与 NoSQL

  • 建立数据库系统

  • 单页应用项目 - URL 缩短器

首先,让我们看看 SQL 和 NoSQL 之间的区别。

SQL 与 NoSQL

SQL 数据库或关系数据库已经存在很长时间;事实上,直到新术语被创造出来之前,数据库大致被假定为 SQL 数据库,这个新术语就是 NoSQL。

好吧,我们正在谈论 SQL 和 NoSQL 之间的高级区别。以下是它们之间的区别:

SQL 数据库(RDBMS)NoSQL 数据库
SQL 数据库是关系数据库(RDBMS)NoSQL 数据库是非关系或分布式数据库
SQL 数据库基于表及其与其他表的关系NoSQL 基于文档、键值对、图数据库或宽列存储
SQL 数据库将数据存储在表的行中NoSQL 是一组键值对、文档、图数据库或宽列存储
SQL 数据库有预定义的模式NoSQL 有动态模式
SQL 数据库是纵向可扩展的NoSQL 数据库是横向可扩展的
SQL 数据库的例子有 MySQL、Oracle、SQLite、PostgreSQL 和 MS SQLNoSQL 数据库的例子有 MongoDB、BigTable、Redis、RavenDB、Cassandra、HBase、Neo4j 和 CouchDB

让我们试着了解一些著名的 SQL 和 NoSQL 数据库的基本特性。

SQL 数据库

以下部分涉及不同的 SQL 数据库及其用法。

MySQL - 开源

作为世界上最流行的数据库之一,MySQL 具有一些优点,使其适用于各种业务问题。以下是 MySQL 的一些重要优点:

  • 复制:MySQL 支持复制,通过复制 MySQL 数据库,可以显著减少一台机器的工作负载,并且可以轻松扩展应用程序

  • 分片:当写操作数量非常高时,分片通过将应用服务器分区来将数据库分成小块,有助于减轻负载

PostgreSQL

如前所述,PostgreSQL 是 Django 社区中最受欢迎的数据库。它也拥有核心支持的数据库中最广泛的功能集。

进化的 PostgresSQL 的高级查询和功能使得将复杂的传统 SQL 查询转换为更简单的查询变得可能。然而,使用传统的 SQL 数据库实现数组、hstore、JSON 等功能有点棘手。

NoSQL 数据库

这个概念是在水平扩展困难且基于 RDBMS 的数据库无法像预期的那样扩展时引入的。它通常被称为 Not only SQL。它提供了一种存储和检索数据的机制,而不是传统的 SQL 方法。

MongoDB

MongoDB 是最受欢迎的基于文档的 NoSQL 数据库之一,它以类似 JSON 的文档存储数据。它是一个非关系数据库,具有动态模式。它是由DoubleClick的创始人开发的。它是用**C++**编写的,目前被一些大公司使用,如纽约时报、Craigslist 和 MTV Networks。以下是 MongoDB 的一些优点和优势:

  • 速度:对于简单的查询,它具有良好的性能,因为所有相关数据都在一个单个文档中,消除了连接操作

  • 可扩展性:它是水平可扩展的,也就是说,您可以通过增加资源池中服务器的数量来减少工作负载,而不是依赖独立的资源

  • 易管理:对开发人员和管理员都很容易使用。这也使得 MondoDB 具有共享数据库的能力

  • 动态模式:它为您提供了在不修改现有数据的情况下演变数据模式的灵活性

CouchDB

CouchDB 也是一种基于文档的 NoSQL 数据库。它以 JSON 文档的形式存储数据。以下是 CouchDB 的一些优点和优势:

  • 无模式:作为 NoSQL 家族的一员,它也具有无模式的特性,使其更加灵活,因为它具有存储数据的 JSON 文档形式

  • HTTP 查询:您可以使用 Web 浏览器访问数据库文档

  • 冲突解决:它具有自动冲突,当您要使用分布式数据库时非常有用

  • 易复制:复制相当简单

Redis

Redis 是另一个开源的 NoSQL 数据库,主要因其闪电般的速度而被广泛使用。它是用 ANSI C 语言编写的。以下是 Redis 的一些优点和优势:

  • 数据结构:Redis 提供了高效的数据结构,有时被称为数据结构服务器。存储在数据库中的键可以是哈希、列表和字符串,并且可以是排序或无序集合。

  • Redis 作为缓存:您可以使用 Redis 作为缓存,通过实现具有有限时间的键来提高性能。

  • 非常快:它被认为是最快的 NoSQL 服务器之一,因为它使用内存数据集。

设置数据库系统

Django 支持多种数据库引擎。然而有趣的是,您只需要学习一个 API 就可以使用任何这些数据库系统。

这可能是因为 Django 的数据库层抽象了对数据库系统的访问。

稍后您将了解这一点,但是现在,您只需要知道无论您选择哪种数据库系统,都可以在不修改的情况下运行本书(或其他地方)开发的 Django 应用程序。

与客户端-服务器数据库系统不同,SQLite 不需要在内存中保留进程,并且将数据库存储在单个文件中,使其非常适合我们的开发环境。这就是为什么我们在整个项目中一直使用这个数据库,直到现在。当然,您可以自由选择使用您喜欢的数据库管理系统。我们可以通过编辑配置文件告诉 Django 使用哪个数据库系统。值得注意的是,如果您想使用 MySQL,您需要安装 MySQL,这是 Python 的 MySQL 驱动程序。

在 Django 中安装数据库系统非常简单;您只需要先安装要配置的数据库,然后在settings.py文件中添加几行配置,数据库设置就完成了。

设置 MySQL

我们将在接下来的几节中逐步安装和配置 MySQL 及其相关插件。

在 Linux - Debian 中安装 MySQL

在 Linux 中执行以下命令安装 MySQL(这里是 Debian):

sudo apt-get install mysql-server 

执行此命令后,将要求您设置 MySQL 并使用用户名和密码配置数据库。

安装 Python 的 MySQL 插件

要安装所需的与 MySQL 相关的插件,请使用以下命令:

pip install MySQL-python 

现在,打开settings.py文件,并添加以下行以使 Django 连接到 MySQL:

DATABASES = {
  'default': {
  'ENGINE': 'django.db.backends.mysql',
  'NAME': 'django_db',
  'USER': 'your_username',
  'PASSWORD': 'your_password',
  }
}

就是这样,现在你需要做的就是在新配置的数据库中重新创建所有表,并运行以下命令:

python manage.py syncdb 

注意

如果您尝试访问未定义的数据库,将会收到django.db.utils.ConnectionDoesNotExist异常。

Django 的优势在于您可以同时在多个数据库中使用它。

然而,您可能会想,为什么在同一个项目中需要多个数据库?

直到 NoSQL 数据库出现之前,在大多数情况下,通常使用同一个数据库来保存所有类型的数据记录,从关键数据(如用户详细信息)到转储数据(如日志);所有这些都保存在同一个数据库中,系统在扩展系统时面临挑战。

对于多数据库系统,一个理想的解决方案可能是将关系信息(例如用户、角色和其他帐户信息)存储在 SQL 数据库(如 MySQL)中。独立的应用程序数据可以存储在 NoSQL 数据库(如 MongoDB)中。

我们需要通过配置文件定义多个数据库。当您想要使用多个数据库与您使用的数据库服务器时,Django 需要告诉您。因此,在settings.py文件中,您需要使用数据库别名映射更改DATABASES设置。

多数据库配置的一个适当示例可以写成如下形式:

DATABASES = {
  'default': {
    'NAME': 'app_data',
    'ENGINE': 'django.db.backends.postgresql_psycopg2',
    'USER': 'postgres_user',
    'PASSWORD': 's3krit'
  },
  'users': {
    'NAME': 'user_data',
    'ENGINE': 'django.db.backends.mysql',
    'USER': 'mysql_user',
    'PASSWORD': 'priv4te'
  }
}

上述示例使用了两个数据库,分别是 PostgreSQL 和 MySQL,具有所需的凭据。

迁移和迁移的需求

迁移允许您通过创建代表模型更改的迁移文件来更新、更改和删除模型,并且可以在任何开发、暂存或生产数据库上运行。

Django 的模式迁移经历了漫长而复杂的历史;在过去的几年里,第三方应用South是唯一的选择。如果您考虑迁移的重要性,Django 1.7 发布时内置了迁移支持。

我们还需要了解 South 与 Django 迁移的区别。对于熟悉 South 的人来说,这应该感觉相当熟悉,可能会更清晰一些。为了方便参考,以下表格比较了旧的 South 工作流程和新的 Django 迁移工作流程:

步骤SouthDjango 迁移
初始迁移运行 syncdb 然后 ./manage.py schemamigration <appname> --initial./manage.py makemigrations <appname>
应用迁移./manage.py migrate <appname>./manage.py migrate <appname>
非首次迁移./manage.py schemamigration <appname> --auto./manage.py makemigration <appname>

因此,从表中我们可以看出,Django 迁移基本上遵循与 South 相同的流程,至少对于标准迁移流程来说,这只是简化了一些事情。

Django 迁移中的新功能

新的迁移代码将是 South 的改进版本,但将基于相同的概念,如下所示:

  • 每个应用程序的迁移

  • 自动检测变化

  • 数据迁移与模式迁移同时进行

让我们看一下以下术语列表,以了解 Django 迁移的优势:

  • 改进的迁移格式:改进的迁移格式可读性更强,因此可以在不实际执行的情况下进行优化或检查

  • 重置基线:在这种情况下,不需要每次保留或执行整个迁移历史,因为现在可以随着项目的增长创建新的第一次迁移

  • 改进的自动检测:新的和自定义字段更改将更容易被检测到,因为迁移将与改进的字段 API 一起构建

  • 更好的合并检测:新的迁移格式将自动解决不同版本控制系统分支之间的合并,如果我们能够合并这些更改,就不再需要任何工作

一旦您设置好项目并启动应用程序,也就是说,您的应用程序已经在数据库中生成了必要的表,您不应该对 Django 模型进行复杂的更改,也就是说,您不应该从一个类中删除属性。然而,在实际情况下,这是不可能的,因为您可能需要相应地更改您的模型类。在这种情况下,我们有一个解决这些问题的方法。这个过程被称为迁移,在 Django 中,这些迁移是通过一个叫做 South 的模块来完成的。

直到 Django 的 1.7 版本,即最新版本,您必须单独安装 south 模块。然而,自 Django 的 1.7 迁移以来,south 模块是一个内置模块。您可能一直在这样做,例如,当您使用以下命令更改(例如添加新属性)您的模型类时:

$python manage.py syncdb 

使用更新版本,manage.py syncdb已经被弃用以进行迁移,但如果您仍然喜欢旧的方式,现在可以使用。

后端支持

这对于任何用于生产的 Django 应用程序来说都是非常重要的,以获得迁移支持。因此,选择一个主要受迁移模块支持的数据库总是一个更好的决定。

一些最兼容的数据库如下:

  • PostgreSQL:在迁移或模式支持方面,PostgresSQL 是最兼容的数据库。

注意

您可以使用null=True初始化新列,因为这样可以更快地添加。

  • MySQL:MySQL 是一个广泛使用的数据库,因为 Django 无缝支持它。这里的问题是,在进行模式更改操作时,没有事务支持,也就是说,如果一个操作失败,您将不得不手动回滚更改。此外,对于每个模式更新,所有表都将被重写,这可能需要很长时间,重新启动应用程序可能需要很长时间。

  • SQLite:这是 Django 默认的数据库,主要用于开发目的。因此,它对以下情况的模式更改支持有限:

  • 创建新表

  • 数据复制

  • 删除旧表

  • 重命名表

如何进行迁移?

迁移主要是通过以下三个命令完成的,如下所示:

  • makemigrations:这是基于您对准备迁移查询的模型所做的更改

  • migrate:这将应用makemigrations查询准备的更改并列出它们的状态。

  • sqlmigrate:这显示了makemigrations查询准备的 SQL 查询

因此,Django 的模式迁移流程可以如下所述:

$python manage.py makemigrations 'app_name'

这将准备迁移文件,其外观类似于以下内容:

Migrations for 'app_name':
  0003_auto.py:
    - Alter field name on app_name

然后,在文件创建后,您可以检查目录结构。您将在migration文件夹下看到一个名为0003_auto.py的文件;您可以使用以下命令应用更改:

$ python manage.py migrate app_name

以下是您需要执行的操作:

Synchronize non migrated apps: sessions, admin, messages, auth, staticfiles, contenttypes
Apply all migrations: app_name
Synchronizing apps without migrations:
Creating tables...
Installing custom SQL...
Installing indexes...
Installed 0 object(s) from 0 fixture(s)
Running migrations:
Applying app_name.0003_auto... OK

OK消息表示迁移已成功应用。

为了使它更容易理解,迁移可以用以下图表来解释:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/lrn-dj-webdev/img/image00312.jpeg

有三个独立的实体:

  • 源代码

  • 迁移文件

  • 数据库

开发人员在源代码中进行更改,主要是在models.py文件中,并修改先前定义的模式。例如,当他们根据业务需求创建一个新字段,或者将 max_length 从 50 更新为 100。

我们将完成项目的适当迁移,以查看这个迁移实际上是如何工作的。

首先,我们必须创建应用程序的初始迁移:

$ python manage.py makemigrations tweet

其输出如下:

Migrations for 'tweet': 
0001_initial.py: 
- Create model HashTag 
- Create model Tweet 
- Add field tweet to hashtag 

这表明初始迁移已经创建。

现在,让我们改变我们的推文模态,现在如下所示:

text = models.CharField(max_length=160, null=False, blank=False)

我们将更改之前的推文模态为:

text = models.CharField(max_length=140, null=False, blank=False)

由于我们已经更改了我们的模式,现在我们必须进行迁移以正确运行应用程序。

从迁移流程中,我们了解到,现在我们必须运行makemigrations命令,如下所示:

$python manage.py makemigrations tweet

其输出如下:

Migrations for 'tweet': 
0002_auto_20141215_0808.py: 
- Alter field text on tweet 

正如你所看到的,它已经检测到了我们字段的更改。

为了验证,我们将打开我们的 SQL 数据库并检查 tweet 表的当前模式。

登录到 MySQL:

$mysql -u mysql_username -pmysql_password mytweets 

在 MySQL 控制台中,写入:

$mysql> desc tweet_tweet;

这将显示 tweet 表的模式,如下所示:

+-------------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | int(11) | NO | MUL | NULL | |
| text | varchar(160) | NO | | NULL | |
| created_date | datetime | NO | | NULL | |
| country | varchar(30) | NO | | NULL | |
| is_active | tinyint(1) | NO | | NULL | |
+--------------+--------------+------+-----+---------+----------------+
6 rows in set (0.00 sec)

由于我们还没有应用我们的迁移,数据库中明显显示字符字段中的文本为 160:

text | varchar(160) | NO | | NULL

我们在应用我们的迁移后将做完全相同的事情:

$python manage.py migrate tweet

以下是我们需要执行的操作:

Apply all migrations: tweet
Running migrations:
Applying tweet.0002_auto_20141215_0808... OK

我们的迁移已成功应用;让我们从数据库中验证一下。

要在tweet_tweet表上运行相同的 MySQL desc命令,请使用以下命令:

mysql> desc tweet_tweet;
+--------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | int(11) | NO | MUL | NULL | |
| text | varchar(140) | YES | | NULL | |
| created_date | datetime | NO | | NULL | |
| country | varchar(30) | NO | | NULL | |
| is_active | tinyint(1) | NO | | NULL | |
+--------------+--------------+------+-----+---------+----------------+
6 rows in set (0.00 sec)

确实!我们的迁移已成功应用:

| text | varchar(140) | YES | | NULL | |

迁移如何知道要迁移什么

Django 永远不会在同一个数据库上运行两次迁移,这意味着它会保留这些信息。这些信息由一个名为django_migrations的表管理,它是在第一次启动 Django 应用程序时创建的,之后每次迁移都会插入一行新数据。

例如,运行我们的迁移后,表格可能会看起来像这样:

mysql> select * from django_migrations;
+----+-------+-------------------------+---------------------+
| id | app | name | applied |
+----+-------+-------------------------+---------------------+
| 1 | tweet | 0001_initial | 2014-12-15 08:02:34 |
| 2 | tweet | 0002_auto_20141215_0808 | 2014-12-15 08:13:19 |
+----+-------+-------------------------+---------------------+

前面的表格显示了有两个带有标记信息的迁移,并且每次迁移时,它都会跳过这些更改,因为这个表中已经有了对应于该迁移文件的条目。

这意味着即使你手动更改迁移文件,它也会被跳过。

这是有道理的,因为通常你不希望运行两次迁移。

然而,如果出于某种原因你真的想要应用两次迁移,你可以简单地删除表格条目中的*“THIS IS NOT A OFFICIALLY RECOMMENDED WAY”*,它将正常工作。

相反,如果你想要撤消特定应用的所有迁移,你可以迁移到一个名为 zero 的特殊迁移。

例如,如果你键入,tweet 应用的所有迁移将被撤销:

$python manage.py migrate tweet zero

除了使用 zero,你还可以使用任意的迁移,如果那个迁移在过去,那么数据库将回滚到那个迁移的状态,或者如果还没有运行该迁移,那么数据库将向前滚动。

迁移文件

那么,迁移文件包含什么,当我们运行以下命令时到底发生了什么?

$python manage.py migrate tweet 

运行完这个命令后,你会看到一个名为migrations的目录,里面存储着所有的迁移文件。让我们来看看它们。由于它们是 Python 文件,可能很容易理解。

打开tweet/migrations/0001_initial.py文件,因为这是初始迁移代码创建的文件。它应该看起来类似于以下内容:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations

class Migration(migrations.Migration):
dependencies = [
  ('user_profile', '__first__'),
]

operations = [
  migrations.CreateModel(
  name='HashTag',
  fields=[
    ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
    ('name', models.CharField(unique=True, max_length=64)),
  ],
  options = {
  },
  bases=(models.Model,),
  ),
  migrations.CreateModel(
  name='Tweet',
  fields=[
    ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
    ('text', models.CharField(max_length=160)),
    ('created_date', models.DateTimeField(auto_now_add=True)),
    ('country', models.CharField(default=b'Global', max_length=30)),
    ('is_active', models.BooleanField(default=True)),
    ('user', models.ForeignKey(to='user_profile.User')),
  ],
  options = {
  },
  bases=(models.Model,),
  ),
  migrations.AddField(
    model_name='hashtag',
    name='tweet',
    field=models.ManyToManyField(to='tweet.Tweet'),
    preserve_default=True,
  ),
]

要使迁移实际工作,必须有一个名为Migration()的类,它继承自django.db.migrations.Migration模块。这是用于迁移框架的主要类,这个迁移类包含两个主要列表,如下所示:

  • 依赖项:这是必须在迁移开始之前运行的其他迁移的列表。在存在依赖关系的情况下,比如外键关系的情况下,外键模型必须在其键被添加到这里之前存在。在前面的情况下,我们对user_profile参数有这样的依赖。

  • 操作:这个列表包含要应用的迁移列表,整个迁移操作可以属于以下类别:

  • CreateModel:从名称本身,很明显这将创建一个新模型。从前面的模型文件中,你可以看到这样的行:

migrations.CreateModel(
name='HashTag',....
migrations.CreateModel(
name='Tweet',..

这些迁移行创建了具有定义属性的新模型。

  • DeleteModel:这将包含从数据库中删除模型的语句。这些与CreateModel方法相反。

  • RenameModel:这将使用给定的新名称从旧名称重命名模型。

  • AlterModelTable:这将更改与模型关联的表的名称。

  • AlterUniqueTogether:这是更改的表的唯一约束。

  • AlteIndexTogether:这将更改模型的自定义索引集。

  • AddField:这只是向现有模型添加新字段。

  • RemoveField:这将从模型中删除字段。

  • RenameField:这将为模型将字段名称从旧名称重命名为新名称。

在更新应用程序时,模式的迁移不是唯一需要迁移的事情;还有另一件重要的事情叫做数据迁移。这是由先前操作已经存储在数据库中的数据,因此也需要迁移。

数据迁移可以在许多情况下使用。其中,最合乎逻辑的情况是:

  • 将外部数据加载到应用程序中

  • 当模型架构发生变化并且数据集也需要更新时

让我们通过从username.txt文件中加载推文来玩耍我们的项目。使用以下命令为我们的项目创建一个空迁移:

$python manage.py makemigrations --empty tweet

这将生成一个名为mytweets/migrations/003_auto<date_time_stamp>.py的迁移文件。

打开这个文件;它看起来像下面这样:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

class Migration(migrations.Migration):

dependencies = [
  ('tweet', '0002_auto_20141215_0808'),
]

operations = [
]

这只是 Django 迁移工具的基本结构,要进行数据迁移,我们必须在操作中添加RunPython()函数,如下所示:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

def load_data(apps, schema_editor):
  Tweet(text='This is sample Tweet',
    created_date=date(2013,11,29),
    country='India',
    is_active=True,
  ).save()

class Migration(migrations.Migration):

dependencies = [
  ('tweet', '0002_auto_20141215_0808'),
]

operations = [
  migrations.RunPython(load_data)
]

就这些了。现在,运行迁移命令:

$python manage.py migrate

这些是您需要执行的操作:

Synchronize unmigrated apps: user_profile
Apply all migrations: admin, contenttypes, tweet, auth, sessions
Synchronizing apps without migrations:
Creating tables...
Installing custom SQL...
Installing indexes...
Running migrations:
Applying contenttypes.0001_initial... FAKED
Applying auth.0001_initial... FAKED
Applying admin.0001_initial... FAKED
Applying sessions.0001_initial... FAKED
Applying tweet.0003_auto_20141215_1349... OK

执行上述命令后,该命令迁移了所有应用程序,并最终应用了我们创建新推文的迁移,从加载的数据中创建了新推文:

mysql> select * from tweet_tweet;
+----+---------+---------------------------------------------+---------------------+---------+-----------+
| id | user_id | text | created_date | country | is_active |
+----+---------+---------------------------------------------+---------------------+---------+-----------+
| 1 | 1 | This Tweet was uploaded from the file. | 2014-12-15 14:17:42 | India | 1 |
+----+---------+---------------------------------------------+---------------------+---------+-----------+
2 rows in set (0.00 sec)

很棒,对吧?

当您有以 JSON 或 XML 文件形式的外部数据时,这种解决方案非常必要。

理想的解决方案是使用命令行参数来获取文件路径并加载数据,如下所示:

$python load data tweet/initial_data.json

不要忘记将迁移文件夹添加到 Git 中,因为它们与源代码一样重要。

Django 与 NoSQL

Django 并不正式支持 NoSQL 数据库,但是在有这么多开发者的伟大社区的支持下,Django 有一个支持MongoDB作为后端数据库的分支。

为了说明问题,我们将使用 Django-Norel 项目来配置 Django 与 MongoDB 数据库。

您可以在django-nonrel.org/找到关于此的详细信息。

可以按照docs.mongodb.org/manual/installation/中提到的步骤安装 MongoDB,根据您的配置。

在这里,我们将为 Linux 的 Debian 版本(具体来说是 Ubuntu)设置 MongoDB。

导入 MongoDB 公共 GPG 密钥:

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10

为 MongoDB 创建一个列表文件:

echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | sudo tee /etc/apt/sources.list.d/mongodb.list

重新加载本地软件包数据库:

sudo apt-get update

安装 MongoDB 软件包:

sudo apt-get install -y mongodb-org

启动 MongoDB:

sudo service mongod start

单页面应用项目 - URL 缩短器

MongoDB 可以与 Django 一起使用的两种方式如下:

  • MongoEngine:这是一个文档对象映射器(类似于 ORM,但用于文档数据库),用于从 Python 与 MongoDB 一起使用。

  • Django non-rel:这是一个支持 Django 在非关系型(NoSQL)数据库上的项目;目前支持 MongoDB。

MongoEngine

在我们继续展示如何配置 MongoEngine 与 Django 之前,需要安装 MongoEngine。通过输入以下命令来安装 MongoEngine:

sudo pip install mongoengine 

为了保护我们之前创建的项目,并更好地理解,我们将创建一个单独的新项目来配置 MongoDB,并且我们将使用现有项目来配置 MySQL:

$django-admin.py startproject url_shortner
$cd url_shortner
$python manage.py startapp url

这将创建项目的基本结构,我们非常了解。

将 MongoDB 连接到 Django

我们将不得不修改settings.py文件,如果我们只在项目中使用 MognoDB,这在这种情况下是正确的,那么我们可以忽略标准数据库设置。我们所要做的就是在settings.py文件上调用connect()方法。

我们将为 MongoDB 放置一个虚拟后端。只需在settings.py文件中替换以下代码,如下所示:

DATABASES = {
  'default': {
  'ENGINE': 'django.db.backends.sqlite3',
  'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
  }
}

用以下内容替换上述代码:

DATABASES = {
  'default': {
  'ENGINE': 'django.db.backends.dummy'
  }
}

Django 中的身份验证

MongoEngine 的优势在于它包括了 Django 身份验证后端。

用户模型成为 MongoDB 文档,并实现了大部分普通 Django 用户模型的方法和属性,这使得 MongoEngine 与 Django 兼容。我们还可以使用身份验证基础设施和装饰器,例如login_required()authentication()方法。auth模块还包含get_user()方法,它接受用户 ID 作为参数并返回用户对象。

要为 MognoEngine 启用此后端,请在settings.py文件中添加以下内容:

AUTHENTICATION_BACKENDS = (
  'mongoengine.django.auth.MongoEngineBackend',
)

存储会话

在 Django 中,您可以使用不同的数据库来存储应用程序的会话。要启用存储在 MongoDB 中的 MongoEngine 会话,settings.py文件中的MIDDLEWARE_CLASSES必须有django.contrib.sessions.middleware.SessionMiddleware参数的条目。还必须在INSTALLED_APPS中有django.contrib.sessions的条目,因为我们是从 Django 的基本结构开始的。

现在,您只需要在settings.py文件中添加以下行:

SESSION_ENGINE = 'mongoengine.django.sessions'
SESSION_SERIALIZER = 'mongoengine.django.sessions.BSONSerializer'

我们现在已经准备好开始一个小型演示项目,在其中我们将在 MongoDB 中实现 URL 缩短项目。

让我们首先创建一个 URL 模型,我们将在其中存储所有长 URL 及其对应的短 URL。

转到以下url/models.py文件:

from django.db import models
from mongoengine import *
connect('urlShortener')

您已经熟悉了上述代码的前两行,它们导入了模块。

第三行,即connect('urlShortener'),将 Django 连接到名为urlShortener的 MongoDB 数据库。

MongoDB 提供了许多连接机制供您选择,它们如下:

from mongoengine import connect
connect('project1')

我们正在使用的方法将 MongoDB 从其默认端口(27017)中获取;如果您在其他端口上运行 MongoDB,请使用connect()方法进行连接:

connect('project1', host='192.168.1.35', port=12345)

如果您为 MongoDB 配置了密码,可以传递参数如下:

connect('project1', username='webapp', password='pwd123')

像 Django 的默认模型字段一样,MongoDB 也为您提供了不同的字段,它们是:

  • BinaryField:此字段用于存储原始二进制数据。

  • BooleanField:这是一个布尔字段类型。

  • DateTimeField:这是一个日期时间字段。

  • ComplexDateTimeField:这样处理微秒,而不是像DateTimeField那样将它们四舍五入。

  • DecimalField:这是一个固定小数点十进制数字段。

  • DictField:这是一个包装了标准 Python 字典的字典字段。这类似于嵌入式文档,但结构未定义。

  • DynamicField:这是一种真正动态的字段类型,能够处理不同和多样化的数据类型。

  • EmailField:这是一个验证输入为电子邮件地址的字段。

  • FileField:这是一个 GridFS 存储字段。

  • FloatField:这是一个浮点数字段。

  • GeoPointField:这是一个存储经度和纬度坐标的列表。

  • ImageField:这是图像文件存储字段。

  • IntField:这是一个 32 位整数字段。

  • ListField:这是一个列表字段,它包装了一个标准字段,允许在数据库中使用字段的多个实例作为列表。

  • MapField:这是一个将名称映射到指定字段类型的字段。这类似于DictField,只是每个项目的“值”必须与指定的字段类型匹配。

  • ObjectIdField:这是 MongoDB 对象 ID 的字段包装器。

  • StringField:这是一个 Unicode 字符串字段。

  • URLField:这是一个验证输入为 URL 等的字段。

注意

默认情况下,字段不是必需的。要使字段成为必需字段,请将字段的 required 关键字参数设置为True。字段还可以具有可用的验证约束(例如,前面示例中的 max_length)。字段还可以采用默认值,如果未提供值,则将使用默认值。默认值可以选择是可调用的,将调用以检索值(如前面的示例)。

可以在docs.mongoengine.org/en/latest/apireference.html上看到完整的不同字段列表。

现在,我们将创建我们的Url()类,它将类似于我们迄今为止创建的其他模型,比如推文等等:

class Url(Document):
full_url = URLField(required=True)
short_url = StringField(max_length=50, primary_key=True, unique=True)
date = models.DateTimeField(auto_now_add=True)

让我们来看一下以下术语列表:

  • full_url:这是一个 URL 字段,将存储完整的 URL,以及触发其短 URL 时请求将重定向的相同 URL

  • short_url:这是相应长 URL 的短 URL

  • date:这将存储Url对象创建的日期。

现在,我们将转到视图并创建两个类:

  • 索引:在这里,用户可以生成短链接。这也将有一个post()方法,保存每个长 URL。

  • 链接:这是短 URL 重定向控制器。当查询短 URL 时,此控制器将请求重定向到长 URL,如下面的代码片段所示:

class Index(View):
def get(self, request):
return render(request, 'base.html')

def post(self, request):
long_url = request.POST['longurl']
short_id = str(Url.objects.count() + 1)
url = Url()
url.full_url = long_url
url.short_url = short_id
url.save()
params = dict()
params["short_url"] = short_id
params['path'] = request.META['HTTP_REFERER']
return render(request, 'base.html', params)

让我们来看一下以下术语列表:

  • get()方法很简单:它将请求转发到base.html文件(我们将很快创建)

  • post()方法从请求的 POST 变量中获取长 URL 并设置对象计数,就像短 URL 保存Url对象到数据库一样:

params['path'] = request.META['HTTP_REFERER'] 

这用于将当前路径传递给视图,以便可以使用锚标记使短 URL 可点击。

这就是这个 URL 对象在数据库中保存的方式:

{ "_id" : ObjectId("548d6ec8e389a24f5ea44258"), "full_url" : "http://sample_long_url", "short_url" : "short_url" } 

现在,我们将继续创建Link()类,它将接受短 URL 请求并重定向到长 URL:

class Link(View):
def get(self, request, short_url):
url = Url.objects(short_url=short_url)
result = url[0]
return HttpResponseRedirect(result.full_url)

short_url参数是来自请求 URL 的short_url代码:

url = Url.objects(short_url=short_url)

前一行查询数据库,检查给定短 URL 的匹配长 URL 是否存在:

return HttpResponseRedirect(result.full_url) 

这将重定向请求以从数据库中查找长 URL。

对于视图,我们需要创建的只是base.html文件。

由于这个项目的目的不是教你用户界面,我们不会包含任何库,并且会尽可能少地使用 HTML 来制作页面。

base.html文件的代码如下:

<!DOCTYPE html>
  <html>
    <head lang="en">
      <meta charset="UTF-8">
      <title>URL Shortner</title>
    </head>
    <body>
      <form action="" method="post">
        {% csrf_token %}
        Long Url:<br>
        <textarea rows="3" cols="80" name="longurl"></textarea>
        <br>
        <input type="submit" value="Get short Url">
      </form>

      <div id="short_url">
      {% if short_url %}
        <span>
          <a href="{{ path }}link/{{ short_url }}" target="_blank">{{ path }}link/{{ short_url }}</a>
        </span>
        {% endif %}
      </div>
    </body>
  </html>

这显示了一个带有表单的文本区域,并在提交表单后,在长 URL 下方显示了短链接。

这就是极简主义 URL 缩短器主页的样子:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/lrn-dj-webdev/img/image00313.jpeg

为了使这个工作,我们现在需要做的就是创建所需的 URL 映射,如下所示:

url_shortner/urlmapping.py

from django.conf.urls import patterns, url
from url.views import Index, Link
from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
url(r'^$', Index.as_view()),
url(r'^link/(\w+)/$', Link.as_view()),
)

摘要

本章的目的是为您准备使用不同数据库创建项目,并为您提供有关数据库迁移以及这些迁移如何工作的基本概念。这不仅将帮助您调试迁移,还可以创建自己的数据迁移脚本,将数据从 JSON 文件或任何其他文件格式直接加载到 Django 应用程序中进行初始化。

本章还为您提供了如何使用 Django 和 MongoDB 设置的基本概念,并且我们还看到了一个小项目演示,随后是在这里使用 MongoDB 扩展 Django 系统的实际应用。

第十二章:使用第三方软件包

现在是时候将我们迄今学到的所有理论和原则结合起来,尝试理解我们如何利用第三方软件包来实现许多可能的项目,比如 Twitter API 的使用,Social Auth 等等。

在本章中,您将学习以下主题:

  • 深入开源世界

  • 在 Django 项目中使用 Social Auth

  • 在 Django 中构建 REST API

除了使用 Django 和 Python 构建网站所需的核心模块之外,我们还需要一些第三方软件包。互联网上有许多免费的第三方软件包;您可以在www.djangopackages.com/找到许多有用的软件包。我们将尝试为我们的项目使用开源第三方软件包。

深入开源世界

当我们看到开源这个词时,首先浮现在我们脑海中的问题是开源实际上是什么意思?

嗯,开源是一个指的是设计公开可访问并且可以根据任何人的需要进行修改,而无需事先获得任何许可的术语。

好的,那么,让我们继续,深入探讨开源世界的各个方面。

什么是开源软件?

开源软件意味着软件的源代码是公开可访问的,因此可以以任何可能的方式进行修改。此外,任何人都可以为源代码做出贡献,这通常会导致软件的增强。

现在,大多数软件用户从未看到源代码,程序员可以修改源代码以满足他们的需求;这基本上意味着程序员手中有源代码可以完全控制软件。

然后程序员可以通过修复任何错误或添加任何新功能来继续使用软件。

开源和其他软件有什么区别?

如果源代码没有公开访问,或者代码只对创建它的特定人群可访问,这种类型的软件称为专有软件闭源软件。闭源软件的例子包括微软产品,如 Microsoft Windows,Word,Excel,PowerPoint,Adobe Photoshop 等。

要使用专有软件,用户必须同意(通常是通过签署许可证,该许可证在第一次运行该软件时显示)他们不会对软件进行任何软件作者未明确允许的操作。

而开源软件是不同的。开源软件的作者将其代码提供给其他人,希望他们可以查看代码,复制代码,从中学习,修改代码或分享代码。Python 和 Django 程序是开源软件的例子。

就像专有软件有许可证一样,开源软件也有许可证,但是有很大的不同。这些许可证促进了开源开发;它们允许修改和修复源代码。

开源难道不只是指某物是免费的吗?

“开源不仅意味着获得访问源代码。”正如开源倡议所解释的那样,这意味着任何人都应该能够修改源代码以满足程序员的需求。

对于开源生态系统可能会有一些误解。程序员可以对他们创建的开源软件收费,但这没有任何意义,因为购买者有权修改并免费分发它。程序员不是为开源软件收费,而是为他们围绕它构建的服务收费,比如支持或其他增值的次要组件。像 Red Hat 这样的公司通过为其开源 Red Hat 操作系统提供支持而收费。Elasticsearch 收费的是一个名为 marvel 的组件,用于监视 Elasticsearch,在 Elasticsearch 运行时非常有帮助。

很多人认为只有互联网上有名的摇滚明星程序员才能为开源项目做出贡献,但事实上,开源社区靠初学者到专家,甚至非程序员的贡献而蓬勃发展。

在 Django 项目中使用 SocialAuth

每个网站都需要存储用户数据,以给他们更好和独特的体验,但为了做到这一点,网站需要你通过填写用户详细信息表格进行注册,他们要求你输入基本信息。填写这些信息可能会很无聊和繁琐。这个问题的一个实际解决方案是Social Auth,通过单击即可从你已经注册的社交网站自动填写你的基本信息注册到网站上。

例如,你可能在浏览网页时看到许多网站提供了一些社交按钮的选项,比如 Google、Facebook、Twitter 等,用于在他们的网站上登录或注册。如果你使用这些社交按钮登录或注册,它们将从社交网站上拉取你的基本信息,比如电子邮件、性别等,这样你就不需要手动填写表格。

单独构建这个完整的端到端实现可能是 Django 中的一个项目,如果你希望你的网站具有相同的功能,你不需要重复造轮子。我们只需导入一个第三方库,在settings.py文件中进行最小的配置更改,就可以让用户通过他们现有的社交账户登录或注册。

OAuth 的工作原理

要理解OAuth的工作原理,让我们考虑以下例子。

OAuth 就像是 Web 的代客泊车钥匙。大多数豪华车都配备了代客泊车钥匙,车主将其交给停车员。有了这把钥匙,车辆就不允许行驶更远的距离,其他功能,比如行李箱和豪华功能都被禁用了。

同样,你在网站上看到的登录按钮并不会给予网站对你社交账户的完全访问权限;它只会传递你授予的详细信息,或者默认信息,比如电子邮件、性别等。

为了访问这些信息,网站过去通常要求用户输入用户名和密码,这增加了个人信息泄露或账户被盗的风险。人们可能会在他们的银行账户上使用相同的用户名和密码,这使得情况更加危险。

因此,OAuth 的目的是为用户提供一种方法,让第三方访问他们的信息,而不用分享密码。通过遵循这种方法,也可以授予有限的访问权限(比如,电子邮件、创建帖子的权限等)。

例如,对于一个登录注册网站,如果他们要求访问你的个人照片,那将会非常奇怪。因此,在使用 OAuth 给予应用程序权限的时候,权限实际上是可以被审查的。

以下图表给出了 OAuth 机制的概述:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/lrn-dj-webdev/img/image00314.jpeg

在上图中,你可以看到需要你的凭据的客户端应用程序要求你使用任何社交账户登录或注册。这在图的第一部分中显示,客户端要求用户进行社交账户授权。

一旦你决定通过社交账户登录,并授予客户端应用程序访问你的社交账户的权限,已经在同一社交网站上注册并拥有自己 API 密钥的客户端应用程序,会向社交网站请求你的用户详细信息。在这个阶段,你可能已经看到了客户端应用程序将访问的记录列表。一些网站也许会让你编辑这些访问权限。在服务器授权客户端应用程序之后,客户端会获得你的社交账户访问的访问令牌。

客户端应用程序可能会存储此访问令牌以供将来使用,或者,如它通常被称为的离线访问

使用此社交 OAuth 方法注册和登录的区别在于,当您已经注册时,客户端应用程序可能会存储您的访问令牌,这样下次尝试登录时,您就不必再次通过相同的社交网站授权页面,因为您已经向他们提供了授权凭据。

实施社交 OAuth

在本节中,我们将学习如何在现有项目中实现社交 OAuth。为了为我们的应用程序实现社交认证,我们将使用一个名为python-social-auth的第三方库。我们将使用 Twitter 社交 Auth 来验证我们的用户。让我们来看一下以下步骤:

  1. 首先,我们将安装名为Python-Social-Auth的第三方应用程序。可以使用以下命令简单地安装python-social-auth
$pip install python-social-auth

  1. 完成安装此第三方库后,我们将转到我们的 mytweet 应用程序,并在settings.py文件中进行配置更改。

我们将此第三方库作为应用程序包含在我们的应用程序中,因此我们必须在INSTALLED_APPS变量中创建此应用程序的条目。

因此,将'social.apps.django_app.default'参数添加到INSTALLED_APPS变量中,如下所示:

INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'user_profile',
'tweet',
'social.apps.django_app.default',
)
  1. 接下来,我们需要在settings.py文件中添加AUTHENTICATION_BACKEND变量,列出我们想要支持的所有社交登录站点。对于此演示,我们将仅添加 Twitter 社交 Auth,但根据用例,您可以添加任何或尽可能多的 Twitter 社交 Auth。AUTHENTICATION_BACKENDS参数是 Python 类路径的列表,它知道如何验证用户。默认情况下指向'django.contrib.auth.backends.ModelBackend'参数。我们将'social.backends.twitter.TwitterOAuth'参数添加到AUTHENTICATION_BACKENDS变量中:
AUTHENTICATION_BACKENDS = (
  'social.backends.twitter.TwitterOAuth',
  'django.contrib.auth.backends.ModelBackend',
)
  1. 我们需要添加TEMPLATE_CONTEXT_PROCESSORS参数,它将在模板的上下文中添加后端和关联数据,这将反过来使用三个条目加载后端密钥,如下所示:
  • 关联:如果用户已登录,则这将是 UserSocialAuth 实例的列表;否则,它将为空。

  • 未关联:如果用户已登录,则这将是未关联后端的列表;否则,它将包含所有可用后端的列表。

  • 后端:这是所有可用后端名称的列表。让我们来看一下以下代码片段:

TEMPLATE_CONTEXT_PROCESSORS = (
'django.contrib.auth.context_processors.auth',
'django.core.context_processors.debug',
'django.core.context_processors.i18n',
'django.core.context_processors.media',
'django.contrib.messages.context_processors.messages',
'social.apps.django_app.context_processors.backends',
)
  1. 我们的 mytweet 应用程序已经有一个用户模型,通过该模型用户可以登录并发布推文。我们将使用相同的模型类来从社交 Auth 创建用户。为此,我们需要添加此行,告诉python-social-auth使用现有的user_profile参数:
SOCIAL_AUTH_USER_MODEL = 'user_profile.User'
  1. 现在,我们将添加用于社交 Auth 的自定义 URL:
SOCIAL_AUTH_LOGIN_REDIRECT_URL = '/profile/'
SOCIAL_AUTH_LOGIN_ERROR_URL = '/login-error/'
SOCIAL_AUTH_LOGIN_URL = '/login/'
SOCIAL_AUTH_DISCONNECT_REDIRECT_URL = '/logout/'

将这些添加到settings.py文件中告诉社交 Auth 在以下情况下使用相应的 URL:

  • SOCIAL_AUTH_LOGIN_REDIRECT_URL:当社交认证成功时,将触发此 URL。我们将使用此 URL 向已登录用户发送他的个人资料页面。

  • SOCIAL_AUTH_LOGIN_ERROR_URL:在社交认证期间出现错误时,将触发此 URL。

  • SOCIAL_AUTH_LOGIN_URL:这是进行社交 Auth 的 URL。

  • SOCIAL_AUTH_DISCONNECT_REDIRECT_URL:用户注销后,将重定向到此 URL。

  1. 由于我们在现有项目中添加了一个新应用程序,因此我们需要在数据库中创建相应的表,这是我们在之前章节中已经学习过的。

现在,我们需要迁移我们的数据库:

$ python manage.py makemigrations
Migrations for 'default':
0002_auto_XXXX_XXXX.py:
- Alter field user on user_profile
$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, default, contenttypes, auth, sessions
Running migrations:
Applying default.0001_initial... OK
Applying default.0002_auto_XXXX_XXXX... OK

  1. 对于最后的配置更改,我们需要向社交 Auth URLs 添加一个条目:
url('', include('social.apps.django_app.urls', namespace='social'))

更新后的 URL 模式将如下所示:

urlpatterns = patterns('',
....
url('', include('social.apps.django_app.urls', namespace='social'))
)

创建 Twitter 应用程序

现在,我们将继续创建一个 Twitter 应用程序,该应用程序将为我们提供 API 密钥,以使这个社交认证工作:

  1. 登录到您的 Twitter 账户并打开apps.twitter.com/app/new

页面将看起来有点像这样:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/lrn-dj-webdev/img/image00315.jpeg

  1. 填写详细信息并创建您的 Twitter 应用程序。

由于我们正在本地测试我们的应用程序,请将http://127.0.0.1:8000/complete/twitter作为回调 URL,并检查允许此应用程序用于使用 Twitter 登录复选框。

当成功创建时,您的应用程序将如下所示:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/lrn-dj-webdev/img/image00316.jpeg

  1. 继续使用Keys and Access Tokens选项卡,并复制Consumer Key(API 密钥)和Consumer Secret(API 密钥)密钥,如下截图所示:https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/lrn-dj-webdev/img/image00317.jpeg

  2. 将以下行添加到settings.py文件中:

SOCIAL_AUTH_TWITTER_KEY = 'your_key'
SOCIAL_AUTH_TWITTER_SECRET = 'your_secret'
  1. 更新我们的用户类以适当地使用 Auth:
class User(AbstractBaseUser, PermissionsMixin):
"""
Custom user class.
"""
  username = models.CharField('username', max_length=10, unique=True, db_index=True)
  email = models.EmailField('email address', unique=True)
  date_joined = models.DateTimeField(auto_now_add=True)
  is_active = models.BooleanField(default=True)
  is_admin = models.BooleanField(default=False)
  is_staff = models.BooleanField(default=False)

  USERNAME_FIELD = 'username'
  objects = UserManager()
  REQUIRED_FIELDS = ['email']
  class Meta:
    db_table = u'user'
    def __unicode__(self):
  return self.username 

importing the PermissionsMixin as from |django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
  1. 现在,启动服务器或打开http://127.0.0.1:8000/login/twitter/

这将带您到以下授权页面:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/lrn-dj-webdev/img/image00318.jpeg

  1. 点击登录按钮,因为我们将使用这个 Twitter 应用程序来登录我们的应用程序。

完成后,它将将请求重定向回 mytweet 应用程序,并显示您的基本信息,如下截图所示:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/lrn-dj-webdev/img/image00319.jpeg

如果用户名在我们的数据库中不存在,它将使用 Twitter 用户名创建用户配置文件。

  1. 让我们创建两条推文并保存它们。https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/lrn-dj-webdev/img/image00320.jpeg

现在,只是为了检查社交认证是否有效,我们将注销并尝试再次打开 URL。重定向后,您将被重定向到相同的先前配置文件页面。

因此,我们学会了如何逐步创建 Twitter API,通过在 Twitter 注册您的应用程序来设置程序中的密钥。然后,我们看到我们的应用程序如何将您发送到 Twitter 网站进行身份验证,以及如何在 Twitter 网站完成身份验证后将您重定向到我们的网站。

在 Django 中构建 REST API

表述性状态转移REST)是 Web 的基本架构原则。遵循 REST 原则的任何 API 都是设计成这样,即这里的浏览器客户端不需要了解 API 的结构。API 服务器只需要响应客户端发出的请求。

HTTP 的工作是应用于资源的动词。一些非常流行的动词是 GET 和 POST,但还有其他重要的动词,比如 PUT,DELETE 等。

例如,我们将使用由 Web 服务管理的 Twitter 数据库作为 REST API。对于所有 REST 通信,媒体类型是 API 服务器必须关心的主要内容,以及它必须响应客户端请求的格式。我们的 API 服务使用基于 JSON 的自定义超媒体,为此我们将分配/json+tweetdb MIME 类型应用程序。

对基本资源的请求将返回如下内容:

Request
GET /
Accept: application/json+tweetdb
Response
200 OK
Content-Type: application/json+tweetdb
{
  "version": "1.0",
  "links": [
    {
      "href": "/tweets",
      "rel": "list",
      "method": "GET" 
    },
    {
      "href": "/tweet",
      "rel": "create",
      "method": "POST"
    }
  ]
}

我们可以通过引用href链接来观察输出,通过这些链接我们试图发送或检索信息,这些链接就是超媒体控制。我们可以通过/user命令和GET请求发送另一个请求来获取用户列表:

Request
GET /user
Accept: application/json+tweetdb
  Response
  200 OK
  Content-Type: application/json+tweetdb

    {
      "users": [
      {
        "id": 1,
        "name": "Ratan",
        "country: "India",
        "links": [
          {
            "href": "/user/1",
            "rel": "self",
            "method": "GET"
          },
          {
            "href": "/user/1",
            "rel": "edit",
            "method": "PUT"
          },
          {
            "href": "/user/1",
            "rel": "delete",
            "method": "DELETE"
          }
        ]
      },
      {
        "id": 2,
        "name": "Sanjeev",
        "country: "India",
        "links": [
        {
          "href": "/user/2",
          "rel": "self",
          "method": "GET"
        },
        {
          "href": "/user/2",
          "rel": "edit",
          "method": "PUT"
        },
        {
          "href": "/user/2",
          "rel": "delete",
          "method": "DELETE"
        }
      ]
    }
  ],
  "links": [
    {
      "href": "/user",
      "rel": "create",
      "method": "POST"
    }
  ]
}

查看前面生成的输出,我们可以猜出所有用户是谁,以及我们可以发送哪些请求,比如DELETEPUT请求。同样,我们甚至可以通过向/user发送POST请求来创建新用户,如下面的代码片段所示:

Request
POST /user
Accept: application/json+tweetdb
  Content-Type: application/json+tweetdb
  {
    "name": "Zuke",
    "country": "United States"
  }
  Response
  201 Created
  Content-Type: application/json+tweetdb
  {
    "user": {
      "id": 3,
      "name": "Zuke",
      "country": "United States",
      "links": [
        {
          "href": "/user/3",
          "rel": "self",
          "method": "GET"
        },
        {
          "href": "/user/3",
          "rel": "edit",
          "method": "PUT"
        },
        {
          "href": "/user/3",
          "rel": "delete",
          "method": "DELETE"
        }
      ]
    },
    "links": {
      "href": "/user",
      "rel": "list",
      "method": "GET"
    }
  }

我们也可以更新现有的数据:

Request
PUT /user/1
Accept: application/json+tweetdb
  Content-Type: application/json+tweetdb
  {
    "name": "Ratan Kumar",
    "country": "United States"
  }
  Response
  200 OK
  Content-Type: application/json+tweetdb
  {
    "user": {
      "id": 1,
      "name": "Ratan Kumar",
      "country": "United States",
      "links": [
        {
          "href": "/user/1",
          "rel": "self",
          "method": "GET"
        },
        {
          "href": "/user/1",
          "rel": "edit",
          "method": "PUT"
        },
        {
          "href": "/user/1",
          "rel": "delete",
          "method": "DELETE"
        }
      ]
    },
    "links": {
      "href": "/user",
      "rel": "list",
      "method": "GET"
    }
  }

正如您可以轻松注意到的那样,我们正在使用不同的HTTP动词(GETPUTPOSTDELETE等)来操作这些资源。

现在,您已经对 REST 的工作原理有了基本的了解,所以我们将继续使用一个名为Tastypie的第三方库来操作我们的 mytweets 应用程序。

使用 Django Tastypie

Django Tastypie 使为 Web 应用程序开发 RESTful API 变得更加容易。

要安装 Tastypie,请运行以下命令:

$pip install django-tastypie

settings.py文件中的INSTALLED_APPS变量中添加tastypie参数。

API 需要许多其他可配置的设置,例如 API 调用的限制等,但默认情况下它们最初设置为默认值。您可以更改这一点,也可以保持不变。

一些您应该了解并根据需要修改的 API 设置如下:

  • API_LIMIT_PER_PAGE(可选):此选项控制 Tastypie 在用户未指定 GET 参数的情况下在view.applies列表中返回的默认记录数。结果的数量不会被resource子类覆盖。

例如:

API_LIMIT_PER_PAGE = 15

这里的默认限制是 20。

  • TASTYPIE_FULL_DEBUG(可选):当发生异常时,此设置控制是否显示 REST 响应还是 500 错误页面。

如果设置为True并且settings.DEBUG = True,将显示500 错误页面。

如果未设置或设置为False,Tastypie 将返回序列化响应。

如果settings.DEBUGTrue,您将获得实际的异常消息和跟踪。

如果settings.DEBUGFalse,Tastypie 将调用mail_admins()函数并在响应中提供一个预定义的错误消息(您可以用TASTYPIE_CANNED_ERROR覆盖)。

例如:

TASTYPIE_FULL_DEBUG = True

默认值为False

  • TASTYPIE_CANNED_ERROR(可选):当发生未处理的异常并且settings.DEBUGFalse时,您可以编写自定义错误消息。

例如:

TASTYPIE_CANNED_ERROR = "it's not your fault, it's our we will fix it soon."

这里的默认值是*“抱歉,无法处理此请求。请稍后重试。”*

  • TASTYPIE_ALLOW_MISSING_SLASH(可选):您可以在不提供最终斜杠的情况下调用 REST API,这主要用于与其他系统迭代 API。

您还必须有settings.APPEND_SLASH = False,以便 Django 不发出 HTTP 302 重定向。

例如:

TASTYPIE_ALLOW_MISSING_SLASH = True

这里的默认值是False

  • TASTYPIE_DATETIME_FORMATTING(可选):此设置配置 API 的全局日期/时间数据。

此设置的有效选项包括:

  • iso-8601

  • DateTime::ISO8601

  • ISO-8601(例如:2015-02-15T18:37:01+0000)

  • iso-8601-strict,与 iso-8601 相同,但会触发微秒

  • rfc-2822

  • DateTime::RFC2822

  • RFC 2822(例如,Sun, 15 Feb 2015 18:37:01 +0000)

TASTYPIE_DATETIME_FORMATTING = 'rfc-2822'

以以下代码为例:

这里的默认值是 iso-8601。

  • TASTYPIE_DEFAULT_FORMATS(可选):这个设置全局配置整个站点的序列化格式列表。

例如:

TASTYPIE_DEFAULT_FORMATS = [json, xml]

默认为[json, xml, yaml,html, plist]。

实施简单的 JSON API

为了创建 REST 风格的架构,我们需要为我们的 tweets 定义资源类,所以让我们在tweets文件夹中创建一个api.py文件,内容如下:

from tastypie.resources import ModelResource
from tweet.models import Tweet

class TweetResource(ModelResource):
class Meta:
queryset = Tweet.objects.all()
resource_name = 'tweet'

我们还需要一个 URL,用于所有 API 请求的 Tweet 资源,因此让我们在urls.py文件中添加一个条目:

from tastypie.api import Api
from tweet.api import TweetResource

v1_api = Api(api_name='v1')
v1_api.register(TweetResource())

urlpatterns = patterns('',
...
url(r'^api/', include(v1_api.urls)),
)

这就是我们创建 tweets 的基本 REST API 所需的全部内容。

现在,我们将根据 REST URL 的变化来看各种输出。在浏览器中打开以下 URL,并观察.json格式的输出。

第一个 URL 将以.json格式显示 Tweet API 的详细信息:

http://127.0.0.1:8000/api/v1/?format=json

{
  "tweet": {
    "list_endpoint": "/api/v1/tweet/",
    "schema": "/api/v1/tweet/schema/"
  }
}

根据第一个输出,我们将调用我们的 tweet API,这将给我们 tweet 信息和其他细节,如下所示:

http://127.0.0.1:8000/api/v1/tweet/?format=json

{
  "meta": {
    "limit": 20,
    "next": null,
    "offset": 0,
    "previous": null,
    "total_count": 1
  },
  "objects": [
    {
      "country": "Global",
      "created_date": "2014-12-28T20:54:27",
      "id": 1,
      "is_active": true,
      "resource_uri": "/api/v1/tweet/1/",
      "text": "#Django is awesome"
    }
  ]
}

我们的基本 REST API 已经准备就绪,可以列出所有的 tweets。如果您查看架构,它会给我们很多关于 API 的细节,比如允许使用哪些 HTTP 方法,输出将是哪种格式,以及其他不同的字段。这实际上帮助我们了解我们可以使用我们的 API 做什么:

http://127.0.0.1:8000/api/v1/tweet/schema/?format=json

{
  "allowed_detail_http_methods": [
    "get",
    "post",
    "put",
    "delete",
    "patch"
  ],
  "allowed_list_http_methods": [
    "get",
    "post",
    "put",
    "delete",
    "patch"
  ],
  "default_format": "application/json",
  "default_limit": 20,
  "fields": {
    "country": {
      "blank": false,
      "default": "Global",
      "help_text": "Unicode string data. Ex: \"Hello World\"",
      "nullable": false,
      "readonly": false,
      "type": "string",
      "unique": false
    },
    "created_date": {
      "blank": true,
      "default": true,
      "help_text": "A date & time as a string. Ex: \"2010-11- 10T03:07:43\"",
      "nullable": false,
      "readonly": false,
      "type": "datetime",
      "unique": false
    },
    "id": {
      "blank": true,
      "default": "",
      "help_text": "Integer data. Ex: 2673",
      "nullable": false,
      "readonly": false,
      "type": "integer",
      "unique": true
    },
    "is_active": {
      "blank": true,
      "default": true,
      "help_text": "Boolean data. Ex: True",
      "nullable": false,
      "readonly": false,
      "type": "boolean",
      "unique": false
    },
    "resource_uri": {
      "blank": false,
      "default": "No default provided.",
      "help_text": "Unicode string data. Ex: \"Hello World\"",
      "nullable": false,
      "readonly": true,
      "type": "string",
      "unique": false
    },
    "text": {
      "blank": false,
      "default": "No default provided.",
      "help_text": "Unicode string data. Ex: \"Hello World\"",
      "nullable": false,
      "readonly": false,
      "type": "string",
      "unique": false
    }
  }
}

一些 API 可能需要授权访问,比如用户资料、账户详情等等。只需添加一个基本授权行,就可以在 Tastypie API 中添加基本的 HTTP 授权:

authentication = BasicAuthentication()

基本的 HTTP 授权可以通过头文件添加:

from tastypie.authentication import BasicAuthentication

这将通过一个基本的 HTTP 请求来请求认证,看起来像下面的截图。一旦成功,当前会话中的所有请求都将得到认证。

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/lrn-dj-webdev/img/image00321.jpeg

这之后,通过演示,展示了如何使用 MongoDB 扩展 Django 系统的真实应用。

摘要

在本章中,您了解了开源以及如何在我们的项目中使用和实现开源的第三方包。现在,您将可以舒适地实现来自 Twitter 的社交认证。您也可以尝试自己实现 Facebook 和 Google+的相同功能。

在下一章中,您将学习更多关于调试技术的知识,当我们在代码中遇到任何错误或警告,或者一些配置问题时,我们需要使用这些技术。您还将学习产品开发工具,比如 Git,Sublime Text 编辑器等等。

第十三章:调试的艺术

在本章中,您将学习关于 Django 的 Web 开发的三个重要内容,每个程序员都应该了解。这些是您在代码出错时需要的概念和技术:

  • 记录

  • 调试

  • IPDB-消除错误的交互方式

记录

每个在生产环境中运行的应用程序都必须启用一些日志记录;如果没有启用,那么很难弄清楚出了什么问题以及问题出现在哪里。

Django 使用 Python 的基本日志记录,因此我们将在以下部分详细介绍 Python 日志记录,并看看我们如何在 Django 中使用日志记录服务。

日志的正式定义是软件中事件的跟踪。开发人员调用日志服务来说明事件已经发生或将要发生。日志可以包括需要跟踪的某些重要变量的描述或值。

Python 的logging模块带有五个基于事件严重性分类的日志函数。这些是debug()info()warning()error()critical()

这些按严重性分类在表格中,从最不严重到最严重:

  • debug():在修复错误时使用,通常包含数据的详细信息。

  • info():当事情按照预期进行时,会记录日志。这基本上告诉执行是否成功。

  • 警告():当发生意外事件时会引发此警告。这实际上并不会停止执行,但可能会在将来停止执行。例如,“磁盘空间不足”。

  • error():这是警告的下一个级别,表示某个函数的执行可能已经停止。

  • critical():这是任何日志函数的最高级别。当发生非常严重的错误时,可能会停止整个程序的执行。

logging模块分为以下四个类别:

  • 记录器:记录器是系统日志消息的入口点。程序将日志信息写入记录器,然后处理是否将其输出到控制台或写入文件。

每个记录器包括前面五个日志函数。写入记录器的每条消息称为日志记录。日志记录包含日志的严重性以及重要的日志变量或详细信息,例如错误代码或完整的堆栈跟踪。

记录器本身具有日志级别,其工作原理是:如果日志消息的日志级别大于或等于记录器的日志级别,则消息将进一步进行日志记录;否则,记录器将忽略该消息。

当记录器对日志的评估进行预处理并且需要处理生成的日志时,消息将传递给处理程序。

  • 处理程序:处理程序实际上决定如何处理日志消息。它们负责对日志记录采取行动,例如写入控制台或文件,或通过网络发送。

与记录器一样,处理程序也有日志级别。如果日志记录的日志级别不大于或等于处理程序的级别,则处理程序将忽略日志消息。

可以将多个处理程序绑定到记录器,例如,可以为将 ERROR 和 CRITICAL 消息发送到电子邮件的记录器添加一个处理程序,而另一个处理程序可以将相同的日志写入文件以供以后调试分析。

  • 过滤器:当日志记录从记录器传递到处理程序时,过滤器会添加额外的评估。默认行为是当日志消息级别达到处理程序级别时开始处理邮件。

此过程可以通过应用过滤器进一步中断进行额外评估。

例如,过滤器只允许一个来源将 ERROR 消息记录到处理程序。

过滤器还可以用于改变日志记录的优先级,以便相应地触发记录器和处理器。

  • 格式化程序:在实际记录日志消息之前的最后一步是格式化程序实际格式化由 Python 格式化字符串组成的日志记录。

为了在我们的应用程序中启用日志记录,我们首先需要创建一个记录器。我们需要在settings.py文件中创建描述记录器、处理器、过滤器和格式化程序的 LOGGING 字典。

有关日志设置的完整文档可以在docs.python.org/2/library/logging.config.html找到。

以下是一个简单日志设置的示例:

# settings.py
LOGGING = {
  'version': 1,
  'disable_existing_loggers': False,
  'formatters': {
    'simple': {
      'format': '%(levelname)s %(message)s'
    },
  },
  'handlers': {
    'file':{
      'level':'DEBUG',
      'class': 'logging.FileHandler',
      'formatter': 'simple',
      'filename': 'debug.log',
    }
  },
  'loggers': {
    'django': {
      'handlers':['file'],
      'propagate': True,
      'level':'INFO',
    },
  }
}

这个日志设置定义了一个用于 Django 请求的记录器(Django),以及一个写入日志文件的处理器(文件)和一个格式化程序。

我们将使用相同的方法来测试我们的mytweet项目的日志记录。

现在,我们需要将记录器的条目添加到我们想要跟踪事件的视图中。

为了测试项目,我们将更新我们的用户资料重定向类,以便在未经授权的用户尝试访问时进行日志记录,以及在注册用户尝试打开 URL 时也进行日志记录。

打开tweet/view.py文件,并将UserRedirect类更改为以下内容:

class UserRedirect(View):
  def get(self, request):
    if request.user.is_authenticated():
      logger.info('authorized user')
      return HttpResponseRedirect('/user/'+request.user.username)
    else:
      logger.info('unauthorized user')
      return HttpResponseRedirect('/login/')

还要用import语句初始化记录器,并将以下代码添加到前面的代码中:

import logging
logger = logging.getLogger('django')

就是这样。现在,打开浏览器,单击 URL http://localhost:8000/profile

如果您尚未登录,将被重定向到登录页面。

现在,打开debug.log文件。它包含未经授权用户的INFO,这意味着我们的记录器工作正常:

INFO unauthorized user

调试

调试是查找和消除错误(bug)的过程。当我们使用 Django 开发 Web 应用程序时,我们经常需要知道在 Ajax 请求中提交的变量。

调试工具有:

  • Django 调试工具栏

  • IPDB(交互式调试器)

Django 调试工具栏

这是一组面板,用于显示当前页面请求/响应的各种信息,当单击面板时会显示更详细的信息。

与其简单地在 HTML 注释中显示调试信息,Django 调试工具以更高级的方式显示它。

安装 Django 调试工具栏

要安装 Django 调试工具栏,请运行以下命令:

$ pip install django-debug-toolbar

安装后,我们需要进行基本配置更改以查看 Django 调试工具栏。

settings.py文件的INSTALLED_APPS变量中添加debug_toolbar参数:

# Application definition
INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'user_profile',
    'tweet',
    'social.apps.django_app.default',
    'tastypie',
    'debug_toolbar',
)

对于一个简单的 Django 项目来说,这已经足够了。当服务器运行在开发模式下时,Django 调试工具栏将自动调整自己。

重新启动服务器以查看 Django 调试工具栏,如下截图所示:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/lrn-dj-webdev/img/image00322.jpeg

如您所见,个人资料页面右侧有一个工具栏。Django 调试工具栏有许多面板,默认安装了一些,您可以在前面的截图中看到,还可以在此安装其他第三方面板。

现在,我们将讨论默认启用的面板:

该面板包含了 Django 开发的一些非常重要的统计信息。它显示了两个表,如前面的截图所示,分别是资源使用浏览器定时

  • 资源使用:显示服务器机器上 Django 的资源消耗。

  • 浏览器时间:这显示了客户端的详细信息。请求和响应时间对于了解代码是否可以优化至关重要,如果渲染过多导致页面加载缓慢,可以查看 domLoading。

  • SettingsPathdebug_toolbar.panels.settings.SettingsPanelsettings.py文件中定义的设置列表为headers

  • 路径debug_toolbar.panels.headers.HeadersPanelhttps://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/lrn-dj-webdev/img/image00325.jpeg

该面板显示 WSGI 环境中的 HTTP 请求和响应头和变量。

该面板显示了从框架中的变量,从视图变量开始,还有ratancs参数变量;然后是CookiesSession,以及 GET 和 POST 变量,因为这些对调试表单提交非常有帮助。

这个面板也非常重要,因为它显示了页面响应的数据库查询。这在应用程序扩展时非常有帮助,因为可以彻底检查查询并将其组合在一起,以减少数据库访问并改善页面响应性能。

这还显示了生成 SQL 调用的代码片段,这在调试应用程序时也非常有帮助。

这将列出从我们在settings.py文件中设置的静态文件位置使用的所有静态文件。

这将列出当前请求使用的模板和上下文。

如果我们启用了缓存,那么这将显示给定 URL 的缓存命中的详细信息。

该面板显示信号列表及其参数和接收器。

  • 日志路径debug_toolbar.panels.logging.LoggingPanel

如果启用了日志记录,那么该面板将显示日志消息,如下截图所示:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/lrn-dj-webdev/img/image00332.jpeg

  • 重定向路径debug_toolbar.panels.redirects.RedirectsPanel

当 URL 发生页面重定向时,启用此功能以调试中间页面。通常不调试重定向 URL,因此默认情况下此功能已禁用。

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/lrn-dj-webdev/img/image00333.jpeg

IPDB - 消灭错误的交互方式

Ipdb是 Python 程序的交互式源代码调试器。

运行以下命令安装 Ipdb:

$pip install ipdb

Ipdb 是调试 Python 应用程序的交互方式。安装 Ipdb 后,要在任何函数中使用它,只需编写以下代码:

import ipdb;ipdb.set_trace()

这行神奇的代码将在代码出现的地方停止整个 Django 执行,并为您提供一个活动控制台,在那里您可以实时查找错误或检查变量的值。

在活动控制台中,Ipdb 的快捷键是:

  • n:这表示下一个

  • ENTER:这表示重复上一个

  • q:这表示退出

  • p <variable>:这是打印值

  • c:这表示继续

  • l:这是你所在的列表

  • s:这是进入子程序的步骤

  • r:这意味着继续执行子程序直到结束

  • !<python 命令>:在活动控制台中运行 Python 命令

总结

这一章涵盖的内容远不止这些。这些只是我们在 Django 项目中要使用的调试基础知识。你学会了如何记录和调试我们的代码,以便更好地进行高效编码实践。我们还看到了如何使用 Ipdb 进行更多的调试。

在下一章中,你将学习部署 Django 项目的各种方法。

第十四章:部署 Django 项目

因此,您在 Web 应用程序上做了很多工作,现在是时候让它上线了。为了确保从开发到生产的过渡顺利进行,必须对应用程序进行一些更改。本章涵盖了以下主题的更改,以帮助您成功启动 Web 应用程序:

  • 生产 Web 服务器

  • 生产数据库

  • 关闭调试模式

  • 更改配置变量

  • 设置错误页面

  • 云上的 Django

生产 Web 服务器

在本书中,我们一直在使用 Django 自带的开发 Web 服务器。虽然这个服务器非常适合开发过程,但绝对不适合作为生产 Web 服务器,因为它没有考虑安全性或性能。因此,它绝对不适合生产环境。

在选择 Web 服务器时有几个选项可供选择,但Apache是迄今为止最受欢迎的选择,Django 开发团队实际上推荐使用它。如何使用 Apache 设置 Django 取决于您的托管解决方案。一些托管计划提供预配置的 Django 托管解决方案,您只需将项目文件复制到服务器上,而其他托管计划则允许您自行配置一切。

如何设置 Apache 的详细信息因多种因素而异,超出了本书的范围。如果您想自己配置 Apache,请查阅 Django 在线文档docs.djangoproject.com/en/1.8/howto/deployment/wsgi/apache-auth/获取详细说明。

在本节中,我们将在 Apache 和mod_wsgi模块上部署我们的 Django 应用程序。因此,让我们首先安装这两个。

运行以下命令安装 Apache:

$sudo apt-get install apache2

mod_wsgi参数是 Apache HTTP 服务器模块,提供符合Web 服务器网关接口WSGI)标准的接口,用于在 Apache 下托管基于 Python 2.3+的 Web 应用程序。

运行以下命令安装mod_wsgi模块:

$sudo aptitude install libapache2-mod-wsgi

使用 Apache 和mod_wsgi模块的 Django 是在生产中部署 Django 的最流行方式。

在大多数情况下,开发机器和部署机器是不同的。因此,建议您将项目文件夹复制到/var/www/html/文件夹,以便您的部署文件具有有限的权限和访问权限。

安装了 Apache 服务器后,请尝试在浏览器中访问localhost,即127.0.0.1。通过这样做,您应该会看到默认的 Apache 页面,如下截图所示:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/lrn-dj-webdev/img/image00334.jpeg

我们必须将 Apache 服务器设置为我们的 Django 项目。为此,我们需要为 Apache 创建configuration文件。

为此,在/etc/apache2/sites-available导航到的sites-available文件夹中创建一个mytweets.conf文件,内容如下:

<VirtualHost *:80>
  ServerAdmin mail@ratankumar.org
  ServerName mytweets.com
  ServerAlias www.mytweets.com
  WSGIScriptAlias / /var/www/html/mytweets/mytweets/wsgi.py
  Alias /static/ /var/www/html/mytweets/static/
  <Location "/static/">
    Options -Indexes
  </Location>
</VirtualHost>

让我们来看看以下术语列表,描述了前面代码片段中使用的各种参数:

  • ServerAdmin:如果您没有配置自定义错误页面,将显示此电子邮件地址,该页面将告诉用户联系此电子邮件地址。

  • ServerName:这是您想在其上运行项目的服务器的名称。

  • ServerAlias:这是您要在项目上运行的站点的名称。

  • WSGIScriptAlias:这是项目的wsgi.py文件的位置,在我们运行第一个命令创建 Django 项目时已经存在。

  • Alias:这是路径别名,磁盘上的文件夹的实际位置被映射为项目目录。

现在,我们需要使用a2ensite命令启用此站点配置,并使用a2dissite命令禁用现有站点配置。

让我们通过以下命令为 Apache 启用mytweets.conf文件:

$a2ensite mytweets.conf

这将启用我们的mytweets.conf文件。你也可以使用以下命令禁用default 000-default.conf配置:

$a2dissite 000-default.conf

注意

验证项目静态文件的文件权限。不要忘记在settings.py文件中允许主机的条目。

现在,重新启动服务器:

$sudo service apache2 restart

这样,Django 现在运行在部署模式下,也就是说,它现在已经准备好投入生产。

生产数据库

到目前为止,我们一直在使用 SQLite 作为我们的数据库引擎。它简单,不需要常驻内存中的服务器。对于小型网站,SQLite 在生产模式下表现良好。然而,强烈建议您在生产中切换到使用客户端-服务器模型的数据库引擎。正如我们在前面的章节中看到的,Django 支持多种数据库引擎,包括所有流行的数据库引擎。Django 团队建议您使用 PostgreSQL,但 MySQL 也应该可以。无论你的选择是什么,你只需要在settings.py文件中更改数据库选项,就可以切换到不同的数据库引擎。

如果你想使用 MySQL,为 Django 创建一个数据库、用户名和密码。然后,相应地更改DATABASE_*变量。其他一切都应该保持不变。这就是 Django 数据库层的全部意义。

关闭调试模式

在开发过程中发生错误时,Django 会呈现一个详细的错误页面,提供大量有用的信息。然而,当应用进入生产阶段时,你不希望用户看到这样的信息。除了让用户感到困惑,如果让陌生人看到这样的信息,你还会面临网站安全问题的风险。

当我们使用django-admin.py mytweets命令时,它为项目创建了所有基本配置,我们在settings.py文件中使用了debug=True参数,当这个模式为True时。Django 会做一些额外的工作来帮助你更快地调试问题。Django 的内存使用更多,因为所有的查询都存储在数据库中的django.db.connection.queries中。

对于每个错误消息,都会显示消息的适当堆栈跟踪,这在生产模式下是不推荐的,因为这可能包含敏感信息,可能会削弱整个 Web 应用程序的安全性。

关闭调试模式非常简单。打开settings.py文件,将DEBUG变量更改为False

DEBUG = False

禁用调试信息还有一个额外的好处;你可以提高网站的性能,因为 Django 不必跟踪调试数据以显示它。

更改配置变量

有许多需要为生产创建或更新的配置变量。生产环境是一个非常恶劣的环境。以下是你应该在部署过程中检查的清单。仔细检查setting.py文件,因为每个设置必须以正确的方式定义,以保持项目的安全。

设置可以是特定于环境的,比如在本地运行设置时。数据库凭据可能会改变,甚至数据库也可能会根据环境而改变。在进行部署过程时,启用可选的安全功能。

启用性能优化。第一步是禁用调试,这会提高网站的性能。如果有一个合适的错误报告机制,一旦DEBUGFalse,就很难知道出了什么问题,所以最好在禁用调试模式后准备好你的日志。

在进行 Django 部署时,必须注意以下关键设置:

  • SECRET_KEY:此密钥必须选择大且随机,并且应保密。事实上,建议您永远不要将此信息保存在settings.py文件或版本控制存储库中。相反,将此信息保存在非版本控制文件中或环境路径中的安全位置:
import os
SECRET_KEY = os.environ['SECRET_KEY']

这将从当前操作系统的环境中导入密钥。另一种建议的方法是从文件中导入,可以使用以下方法完成:

with open('/etc/secret_key.txt') as f:
    SECRET_KEY = f.read().strip()
  • ALLOWED_HOSTS:这必须具有有效的主机配置。当调试模式关闭时,这用于保护 CSRF 攻击:
ALLOWED_HOSTS = [
    '.example.com',  # Allow domain and subdomains
    '.example.com.',  # Also allow FQDN and subdomains
]
  • ADMINADMIN键保存站点管理员的名称和电子邮件地址。您将在settings.py文件中找到它,注释如下:
ADMINS = (
# ('Your Name', 'your_email@domain.com'),
)

在此处插入您的姓名和电子邮件地址,并删除#符号以取消注释,以便在发生代码错误时接收电子邮件通知。

DEBUG=False并且视图引发异常时,Django 将通过电子邮件向这些人发送完整的异常信息。

  • EMAIL:由于您的生产服务器的电子邮件服务器很可能与您的开发机器不同,因此您可能需要更新电子邮件配置变量。在settings.py文件中查找以下变量并更新它们:

  • EMAIL_HOST

  • EMAIL_PORT

  • EMAIL_HOST_USER

  • EMAIL_HOST_PASSWORD

此外,您的 Web 应用程序现在有自己的域名,因此您需要更新以下设置以反映这一点:SITE_HOSTDEFAULT_FROM_EMAIL

最后,如果您使用缓存,请确保在CACHE_BACKEND参数中设置正确的设置(理想情况下是memcached参数);在生产环境中,您不希望开发后端出现在这里。

设置错误页面

在调试模式禁用时,您应该为错误页面创建模板,特别是这两个文件:

  • 404.html:当请求的 URL 不存在时(换句话说,当页面未找到时,例如未捕获的异常时),将显示此模板。

创建两个文件,内容随意。例如,您可以在404.html模板中放置一个“页面未找到”的消息,或者一个搜索表单。

  • 500.html:当发生内部服务器错误时,将显示此模板。

建议您通过从站点的基本模板派生它们,使这些模板具有一致的外观。将模板放在templates文件夹的顶部,Django 将自动使用它们。

这应涵盖对生产至关重要的配置更改。当然,此部分并非穷尽一切,还有其他您可能感兴趣的设置。例如,您可以配置 Django 在请求的页面未找到时通过电子邮件通知您,或者提供可以查看调试信息的 IP 地址列表。有关这些以及更多信息,请参阅settings.py文件中的 Django 文档。

希望本节能够帮助您使从开发到生产的过渡更加顺利。

云上的 Django

Web 开发中的部署方式随着时间的推移发生了变化。大多数初创公司正在转向云设置,远离传统的 VPS 托管方法,这是因为可靠性、性能和易于扩展性。

提供基础设施即服务IAS)的最受欢迎的云平台是 Amazon EC2 和 Google Compute Engine。

然后,我们还有其他众所周知的选项,例如平台即服务PaaS),在这种服务中,您可以像将代码推送到普通存储库一样将代码推送,以便自动部署。这些包括 Google App Engine、Heroku 等。

让我们逐一介绍它们。

EC2

EC2上部署很简单。按照给定的步骤在 EC2 上部署所需的设置:

  1. 为 AWS 创建一个帐户。请访问aws.amazon.com并单击创建免费帐户,如下面的屏幕截图所示:https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/lrn-dj-webdev/img/image00335.jpeg

  2. 注册并添加信用卡以获取结算明细。完成后,登录,您将看到一个仪表板。为了部署,我们需要在 AWS 上创建一个名为 EC2 实例(它可以被视为服务器)的服务器。

  3. 点击 EC2(在左上角),如下截图所示:https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/lrn-dj-webdev/img/image00336.jpeg

如前面的截图所示,我已经有一个正在运行的实例(1 Running Instances)。单击启动实例以创建新实例。这将显示可用的 AWS 映像(类似于 VMware 中的截图或上次备份的磁盘):

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/lrn-dj-webdev/img/image00337.jpeg

  1. 向下滚动以选择 Ubuntu 64 位实例(Ubuntu 服务器)。

接下来,选择一个实例类型;最初,选择免费套餐,这是 AWS 为每个新帐户提供的t2.micro实例类型。检查其他设置,因为大多数设置都保持默认值。转到标签实例并为您的实例命名:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/lrn-dj-webdev/img/image00338.jpeg

  1. 接下来要做的重要事情是选择安全组。AWS 具有此功能,可保护您的服务器免受攻击。在这里,您可以配置哪些特定端口将是公开可访问的。基本上,您需要打开两个端口以使推文公开可访问。

  2. 您应该使用 SSH(端口 22)从本地机器连接系统以部署代码。

  3. HTTP(端口 80)用于运行您的 Django 服务器。

注意

由于我们将使用的数据库运行在同一实例上,因此我们不会将 MySQL 端口添加到安全组中。

确保您已经配置了类似以下内容:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/lrn-dj-webdev/img/image00339.jpeg

接下来,审查并启动实例。此外,您必须创建一个密钥对以通过 SSH 访问您的 AWS 机器。密钥是一个.pem文件,您将使用它与 SSH 远程登录到您的机器。创建一个密钥对并下载.pem文件。

注意

确保PEM文件具有特定的 400 权限。如果要使 SSH 工作,您的密钥文件不得公开可见。如有需要,请使用以下命令:chmod 400 mykey.pem

这将需要一段时间,并且将作为正在运行的实例重新显示在您的仪表板上。

单击屏幕左侧的实例。然后,您可以看到正在运行的实例。单击实例行以在屏幕底部获取更多详细信息,如下图所示:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/lrn-dj-webdev/img/image00340.jpeg

在详细信息的右侧,您可以看到公共 DNS:和公共 IP:。这就是您需要的一切(当然还有.pem文件)来登录到您的实例。

在您的机器上,转到终端中下载PEM文件的文件夹,并在终端上键入$ssh -i <pemfilename>.pem ubuntu@<pubic IP>

否则,输入以下内容:

$ssh -i <pemfilename>.pem ubuntu@<public Dns>

通过这样做,您将登录到远程服务器。

这是您从头开始的在线系统。如果要从本地机器部署网站,则可以转到以前的章节并安装虚拟环境所需的一切。Django 和 Apache 在此服务器上执行部署。

部署后,使用我们用于 SSH 的公共 IP,您应该看到已部署的服务器。

谷歌计算引擎

谷歌计算引擎的工作原理与 AWS EC2 相同。目前,谷歌计算引擎没有免费套餐。

谷歌服务器以其可靠性和性能而闻名。因此,如果您考虑具有此需求的项目,请选择它们。

谷歌云为您提供了一个云 SDK 来使用其实例,并且大部分初始配置可以从终端完成。

要在谷歌计算引擎上创建一个实例,请转到:

cloud.google.com/compute/docs/quickstart

此链接将帮助您设置在 Apache 服务器上运行的实例。

红帽开源混合云应用平台

红帽提供了另一种云部署解决方案,免费使用一定限额,名为 OpenShift 的服务。

您可以创建一个 OpenShift 帐户,并从www.openshift.com/app/account/new获取一个免费的基本 3 dynamo 云服务器。

创建帐户后,您可以转到openshift.redhat.com/app/console/applications并添加您的帐户。

OpenShift 为您提供了一个已经设置好版本控制的 Django 存储库。

您只需要进行更改并推送代码。它将自动部署代码。

OpenShift 还提供 SSH 功能,可以登录到您的云服务器,并进行一些基本的故障排除。

Heroku

这也是一个很好的平台,可以顺利地将您的 Django 代码部署到云端。与谷歌计算引擎一样,Heroku 还为您提供了一个 SDK 工具,可以从本地终端安装并执行配置更改。您需要获取一个工具包(Heroku 的 SDK)。

signup.heroku.com上创建一个 Heroku 帐户。

以下是从devcenter.heroku.com/articles/getting-started-with-python中获取的步骤。查看最新更新。以下步骤解释了如何创建和使用 Heroku:

  1. 首先,我们需要安装 Heroku Toolbelt。这为您提供了访问 Heroku 命令行实用程序的权限:
$wget -qO- https://toolbelt.heroku.com/install-ubuntu.sh | sh

将出现以下屏幕:

https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/lrn-dj-webdev/img/image00341.jpeg

  1. 它将在本地机器上安装 Heroku Toolbelt。从命令行登录到 Heroku:
$heroku login

  1. 使用与 Web 登录相同的用户名和密码。让我们来看一下下面的截图:https://github.com/OpenDocCN/freelearn-python-zh/raw/master/docs/lrn-dj-webdev/img/image00342.jpeg

  2. 现在,访问devcenter.heroku.com/articles/getting-started-with-django来在 Heroku 上部署 Django。

谷歌应用引擎

谷歌应用引擎的工作方式不同,它不使用传统的数据库,而是有自己的数据库。因此,要在谷歌应用引擎上部署 Django,我们将使用一个名为 Django-nonrel 的单独项目。

Django-nonrel 是一个允许开发人员在非关系数据库上运行原生 Django 项目(包括 Django 的 ORM)的项目,其中之一就是谷歌应用引擎的数据存储。这是除了 Django 一直支持的标准传统 SQL 数据库之外的所有内容。谷歌应用引擎确实具有一些 Django 支持,但该支持主要涉及模板和视图。对于其他允许快速开发的工具,例如表单、内置管理界面或 Django 身份验证,这些都无法直接运行。Django-nonrel 改变了这一点,为 Django 开发人员提供了支持。

总结

本章涵盖了各种有趣的主题。您了解了几种在部署 Django 时有用的基于 Django 的部署选项。您还学会了如何将 Django 项目从开发环境迁移到生产环境。值得注意的是,您学到的这些框架都非常易于使用,因此您将能够在将来的项目中有效地利用它们。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值