Skip to content

Latest commit

 

History

History
997 lines (675 loc) · 36.3 KB

File metadata and controls

997 lines (675 loc) · 36.3 KB

十一、数据库连接

Django 是一个数据库不可知框架,这意味着 Django 提供的数据库字段被设计为跨不同的数据库工作,例如SQLiteOracleMySQLPostgreSQL。事实上,它们还可以处理多个第三方数据库后端。PostgreSQL 是 Django 在生产中的一个很好的数据库,而 SQLite 用于开发环境,如果您不想在项目中使用 RDBMS,那么您将完成大量工作。本章将向您详细介绍这两种类型之间的区别,并向您展示哪个更适合 Django,以及我们如何在 Django 项目中实际实现它们。

以下是我们将在本章中讨论的主题:

  • SQL 与 NoSQL
  • Django 与关系数据库
  • Django 与 NoSQL
  • 建立数据库系统
  • 单页应用项目 URL 缩短器

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

SQL 与 NoSQL

SQL 数据库或关系数据库已经存在很长时间了;事实上,在新术语 NoSQL 出现之前,这些数据库基本上都被假定为 SQL 数据库。

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

|

SQL 数据库(RDBMS)

|

NoSQL 数据库

| | --- | --- | | SQL 数据库是关系数据库(RDBMS) | NoSQL 数据库是非关系数据库或分布式数据库 | | SQL 数据库基于表及其与其他表的关系 | NoSQL 是基于文档、键值对、图形数据库或宽列存储 | | SQL 数据库将其数据存储在表的行中 | NoSQL 是键值对、文档、图形数据库或宽列存储的集合 | | SQL 数据库具有预定义的模式 | NoSQL 有一个动态模式 | | SQL 数据库是垂直可伸缩的 | NoSQL 数据库是水平可伸缩的 | | SQL 数据库示例有 MySQL、Oracle、SQLite、PostgreSQL 和 MS SQL | NoSQL 数据库示例有 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 的数据库无法像预期的那样扩展时引入的。它通常被称为不仅仅是 SQL。它提供了一种不同于传统 SQL 方法的存储和检索数据的机制。

蒙哥达

MongoDB 是最流行的基于文档的 NoSQL 数据库之一,因为它将数据存储在类似 JSON 的文档中。它是一个具有动态模式的非关系数据库。由双击的创始人开发。它是在 TytT5 中写成的,目前正在被一些大公司使用,如纽约时报、Craigslist 和 MTV 网络。以下是 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 中安装 MySQL–Debian

执行以下命令在 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 发布时内置了对迁移的支持。

我们还需要了解南方移民和 Django 移民。对于那些熟悉南方的人来说,这应该是非常熟悉的,而且可能会更干净一点。为便于参考,下表将旧的 South 工作流与新的 Django 迁移工作流进行了比较:

|

台阶

|

南方

|

Django 迁移

| | --- | --- | --- | | 初始迁移 | 运行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 的改进版本中,但将基于相同的概念,如下所示:

  • 每个应用的迁移
  • 自动检测更改
  • 数据迁移与模式迁移

让我们看看下面的 To0T0 术语列表,了解 Dyango 迁移的优势:

  • 改进后的迁移格式:改进后的迁移格式可读性好,可以在不实际执行的情况下进行优化或检查
  • 重定基址:在这种情况下,不需要每次都保存或执行整个迁移历史,因为随着项目的发展,现在可以创建新的第一次迁移
  • 改进的自动检测:新的和自定义的字段更改将更容易检测,因为迁移将内置改进的字段 API
  • 更好的合并检测:新的迁移格式将自动解决不同 VCS 分支之间的合并问题,如果我们能够合并更改,则不再需要任何工作

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

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

$python manage.py syncdb 

对于较新的版本,manage.py syncdb已经不推荐用于迁移,但是如果您仍然喜欢旧的方式,现在就可以使用。

后端支持

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

以下是一些最兼容的数据库:

  • PostgreSQL: In terms of migration or schema support, PostgresSQL is the most compatible database out there.

    您可以使用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消息表示迁移已成功应用。

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

How to do migrations?

有三个独立的实体:

  • 源代码
  • 迁移文件
  • 数据库

开发人员更改源代码,主要是在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 

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

现在,让我们更改 tweet 模式,如下所示:

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

我们将前面的 tweet 模式更改为:

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 数据库并检查推特表的当前模式。

以以下身份登录 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表上运行相同的 MySQLdesc命令,请使用以下命令:

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 |
+----+-------+-------------------------+---------------------+

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

这意味着,即使手动更改迁移文件,也将跳过该文件。

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

但是,如果出于某种原因确实希望应用两次迁移,只需删除表项*“这不是官方推荐的方式”*,即可。

相反,如果要撤消特定应用的所有迁移,可以迁移到称为零的特殊迁移。

例如,如果键入,tweet 应用的所有迁移都将被反转:

$python manage.py migrate tweet 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: From the name itself, it's very clear that this will create a new model. From the preceding model file, you can see lines such as:

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

      这些迁移线使用定义的属性创建新模型。

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

    • RenameModel:此使用旧名称中给定的新名称重命名模型。

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

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

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

    • AddField:此只是在现有模型中添加了一个新字段。

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

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

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

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

  • 将外部数据加载到应用
  • 当模型模式发生更改并且数据集也需要更新时

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

$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)
]

仅此而已。现在,运行 migrate 命令:

$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

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

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 确实有一个 fork,它将MongoDB作为后端数据库。

为了便于说明,我们将使用 Django Norel 项目配置 Django 和 MongoDB 数据库。

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

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

在这里,我们将为 Debian 版本的 Linux(特别是 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:这是一个在非关系(NoSQL)数据库上支持 Django 的项目;目前它支持 MongoDB

蒙戈发动机

在我们进一步介绍如何使用 Django 配置 MongoEngine 之前,需要安装 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;如果您在其他端口上运行 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 等。

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

不同字段的完整列表见http://docs.mongoengine.org/en/latest/apireference.html

现在,我们将创建我们的Url()类,它将类似于我们目前创建的其他模型,如 tweets 等:

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对象的日期

现在,我们将查看并创建两个类:

  • 索引:在这里,用户可以生成短 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 对象在 DB 中的保存方式:

{ "_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 shortner 主页的外观:

Storing sessions

为了实现这一点,我们现在需要做的就是创建所需的 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 应用以对其进行初始化。

本章还向您介绍了如何使用 MongoDB 设置 Django 的基本概念,我们还看到了一个小项目演示,随后是使用 MongoDB 扩展 Django 系统的实际应用。