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 数据库(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 数据库及其用法。
作为世界上最受欢迎的数据库之一,MySQL 有一些优点,使其适合于各种业务问题。以下是 MySQL 的几个重要优点:
- 复制:MySQL 支持复制,即通过复制一个 MySQL 数据库,可以从一台机器上显著降低工作负载,并且可以轻松扩展应用
- 分片:当写入操作的数量非常高时,分片通过将应用服务器划分成小块来帮助实现
如前所述,PostgreSQL 是 Django 社区中最流行的数据库。它还拥有最广泛的核心支持数据库功能集。
PostgresSQL 的高级查询和功能的发展使我们能够将传统 SQL 查询的复杂行转换成更简单的行来编写查询。然而,对于传统的 SQL 数据库,数组、hstore、JSON 等的实现有点棘手。
这个概念是在水平扩展困难,基于 RDBMS 的数据库无法像预期的那样扩展时引入的。它通常被称为不仅仅是 SQL。它提供了一种不同于传统 SQL 方法的存储和检索数据的机制。
MongoDB 是最流行的基于文档的 NoSQL 数据库之一,因为它将数据存储在类似 JSON 的文档中。它是一个具有动态模式的非关系数据库。由双击的创始人开发。它是在 TytT5 中写成的,目前正在被一些大公司使用,如纽约时报、Craigslist 和 MTV 网络。以下是 MongoDB 的一些优点和优势:
- 速度:对于简单的查询,它提供了良好的性能,因为所有相关数据都在一个文档中,消除了连接操作
- 可扩展性:它是水平可扩展的,也就是说,您可以通过增加资源池中的服务器数量来减少工作负载,而不是依赖独立的资源
- 可管理:开发人员和管理员都可以轻松使用。这也使 MondoDB 能够共享数据库
- 动态模式:它为您提供了在不修改现有数据的情况下发展数据模式的灵活性
CouchDB 也是一个基于文档的 NoSQL 数据库。它以 JSON 文档的形式存储数据。以下是 CouchDB 的一些优势和:
- 无模式:作为 NoSQL 家族的一员,它还具有无模式属性,这使得它更加灵活,因为它以 JSON 文档的形式存储数据
- HTTP 查询:您可以使用 web 浏览器访问您的数据库文档
- 冲突解决:具有自动冲突功能,在使用分布式数据库时非常有用
- 简单复制:复制相当简单
Redis 是另一个开源的 NoSQL 数据库,主要是因为它的轻量级速度。它是用 ANSI C 语言编写的。以下是 Redis 的优势:
- 数据结构:Redis 提供高效的数据结构,有时被称为数据结构服务器。存储在数据库中的键可以是散列、列表和字符串,也可以是排序集或未排序集。
- Redis 作为缓存:您可以通过在有限的时间内实现密钥来使用 Redis 作为缓存,以提高性能。
- 极快:它被认为是最快的 NoSQL 服务器之一,因为它可以处理内存数据集。
Django 支持多个数据库引擎。然而,有趣的是,为了使用这些数据库系统中的任何一个,您只需要学习一个 API。
这可能是因为 Django 的数据库层抽象了对数据库系统的访问。
稍后您将了解这一点,但现在,您只需要知道,无论您选择哪种数据库系统,您都能够运行本书(或其他地方)中开发的 Django 应用,而无需修改。
与客户机-服务器数据库系统不同,SQLite 不需要内存中的常驻进程,它将数据库存储在单个文件中,非常适合我们的开发环境。这就是为什么我们一直在这个项目中使用这个数据库,直到现在。当然,您可以自由使用首选的数据库管理系统。通过编辑配置文件,我们可以告诉 Django 使用哪个数据库系统。另外值得注意的是,如果您想使用 MySQL,您需要安装 MySQL,这是 Python 的 MySQL 驱动程序。
在 Django 中安装数据库系统非常简单;您只需首先安装要配置的数据库,然后在settings.py
文件中添加一些配置行,就完成了数据库设置。
我们将在下面的章节中逐步安装和配置 MySQL 及其相关插件。
执行以下命令在 Linux 中安装 MySQL(此处为 Debian):
sudo apt-get install mysql-server
执行此命令后,将要求您设置 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 相同的过程,至少对于标准迁移过程来说,这只是稍微简化了一些事情。
新的迁移代码将在 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
消息表示迁移已成功应用。
为了让更容易理解,可以用下图来解释迁移:
有三个独立的实体:
- 源代码
- 迁移文件
- 数据库
开发人员更改源代码,主要是在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 确实有一个 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
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
这将创建项目的基本结构,我们非常清楚。
我们将不得不修改文件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'
}
}
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 时请求将重定向到的同一 URLshort_url
:对应长 URL 的短 URLdate
:这将存储创建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 主页的外观:
为了实现这一点,我们现在需要做的就是创建所需的 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 系统的实际应用。