文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Django 和 SQL:数据库扩展好帮手

2024-11-30 10:37

关注

然而,尽管 Django 承担了创建数据库应用的重任,我们依然需要承担数据库的日常管理和监控工作。好在只要使用诸如 Linode Managed Databases 这样的托管数据库服务,很多管理任务都可以委托给云提供商,但我们可能依然会在应用扩展的过程中遇到新问题,例如:

如果其中一个数据库使用了 SQL,我们可以按照《如何用 Django 搞定 SQL 的 脏活累活》一文的介绍,大幅简化海量数据的处理工作。

本文将介绍数据库管理工作中的两个重要概念,并通过循序渐进的指南告诉大家该如何构建面向生产环境的 Django 应用程序。

延伸阅读,了解Akamai cloud-computing

出海云服务,选择Akamai Linode!

数据库迁移

在刚上手时,为数据库中不同列的内容确定适合的数据类型,这可能是个有点棘手的任务,如果有关数据的需求会随着时间推移不可避免产生变化,感觉就更棘手了。如果希望字段只能包含 80 个字符该怎么办?如果需要添加一个时间戳字段以便准确追踪每个内容是在什么时候加入数据库的又该怎么办?

在创建好一个表之后再更改其内容,可能会产生一些非常混乱的后果,原因主要在于:

好在对于 Django 开发者来说,可以使用 makemigrations 和 migrate。一起看看它们是如何生效的。

以如下的 Django 数据模型为例:

class BlogArticle(models.Model):
 user = models.ForeignKey(User, default=1, on_delete=models.SET_DEFAULT)
 title = models.CharField(max_length=120)
 slug = models.SlugField(blank=True, null=True)
 content = models.TextField(blank=True, null=True)
 publish_timestamp = models.DateTimeField(
 auto_now_add=False,
 auto_now=False,
 blank=True,
 null=True,
 )

先来添加一个字段:

updated_by = models.ForeignKey(
 User, related_name="editor", null=True, blank=True, on_delete=models.SET_NULL
)

该字段可供我们追踪修改了模型的最后一个用户。

接着更新一下这个模型:

class BlogArticle(models.Model):
 user = models.ForeignKey(User, default=1, on_delete=models.SET_DEFAULT)
 title = models.CharField(max_length=120)
 slug = models.SlugField(blank=True, null=True)
 content = models.TextField(blank=True, null=True)
 publish_timestamp = models.DateTimeField(
 auto_now_add=False,
 auto_now=False,
 blank=True,
 null=True,
 )
 # our new field
 updated_by = models.ForeignKey(
 User, related_name="editor", null=True, blank=True, on_delete=models.SET_NULL
 )

当我们保存了 BlogArticle 类所声明的文件(models.py)后,如何让数据库知道发生了这个改动?有两种方法:

一起看看这两个命令的作用吧。

1.python manage.py makemigrations

python manage.py makemigrations 可以在我们的 Django 项目中寻找对 models.py 文件进行的所有改动。如果找到改动,将创建一个全新的 Python 文件,其中包含 SQL 数据库需要进行的提议变更(Proposed change)。这种提议变更看起来类似这样:

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
 dependencies = [
 migrations.swappable_dependency(settings.AUTH_USER_MODEL),
 ('articles', '0001_initial'),
 ]
 operations = [
 migrations.AddField(
 model_name='article',
 name='updated_by',
 field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='editor', to=settings.AUTH_USER_MODEL),
 ),
 ]

这当然也是另一个 Python 文件。开发者可以通过该文件了解数据库中应该发生的事情。为了维持一致并利用 Django ORM 的内置功能,该文件会使用 Python 编写(而非 SQL)。

但为什么这个文件中记录了应该发生的事情?主要原因在于:

假设这些变更是有效的(只要我们可以正确判断),随后就可以通过下列方法提交这些变更了。

2.python manage.py migrate

python manage.py migrate 将尝试着为我们更改数据库(所有字段、列、表、外键等),Django 会代替我们做这些工作,以确保数据库能按照我们希望的方式更新。

需要注意的是,Django 可能会因为一些原因而无法执行这些变更。对于新接触 Django 的开发者,最主要的原因往往是添加或删除了字段 / 列,但未能正确进行迁移。

如果操作正确无误,python manage.py migrate 可以保证产生稳定的系统,并且各方面均与我们的 Python 代码和 SQL 表保持匹配,从而确保可以正确发挥出 Django 和 SQL 数据库提供的强大功能。

这种做法如何为我们带来更高灵活性?

Python 有着广泛的应用,但 SQL 就未必了。顾名思义,结构化查询语言(Structured Query Language)存在一些固有的局限。谁能只使用 SQL 就创建出精彩的动画电影呢?

这样说的意图在于,Python 的简洁性有助于开发者发挥出 SQL 的真正威力,甚至可能是在不知不觉中发挥出来的。

为何使用托管数据库和 Django 是合理的做法

在创建包括 Django 在内的 Web 应用程序时,我们需要决定一些事情,例如:

  1. 需要怎样的一种或多种数据存储解决方案?MySQL、Postgres、MongoDB、Redis、Object Storage……
  2. 如何运行以及与数据存储解决方案进行集成?
  3. 如何从中断或停机中恢复?
  4. 如何维护存储解决方案?
  5. 如何保护存储解决方案?
  6. 如何备份存储解决方案?

上述这些问题的答案可能会随着项目复杂性的提高而改变,但所有答案都始于同一个地方:决定到底是使用自管理的还是第三方托管的存储解决方案。

自管理数据库:

托管服务往往从一开始就需要付出更多成本,而自行管理意味着我们可以使用自己喜欢,并且以某种方式(或在某种程度上)针对我们的需求进行了优化的 Linux 发行版。例如我们可以用自己团队创建并修改的 MySQL 分支版本。自行运行的服务往往更省钱,但需要付出更多的时间和精力来维护。

第三方托管数据库服务:

没错,这类服务往往成本更高一些,但可以大幅减少我们需要投入的维护时间。这种方式以及托管式的数据存储解决方案已经成为很多 Web 应用程序的首选。本例中,我们已经在使用 Django 来管理数据库事务,SQLAlchemy 也具备类似优势,因为它可以配合 FastAPI、Flask 等框架一起使用。如果你已经将 SQL 的相关开发工作通过 Python 包来实现,那么为何不把 SQL 服务器的运行也照此处理?

考虑到 Python ORM(例如 Django ORM 和 SQLAlchemy)的效果,建议尽可能使用托管数据库和 / 或托管的数据存储服务,从而可以获得下列这些收益:

实现上述好处的前提是:在 Linode 平台上使用托管的 MySQL 数据库集群,并使用 Linode 的 Object Storage(存储 CSS、JavaScript、图像、视频等文件)。实际上,使用这些服务还有助于我们将更多精力专注于通过 Django、 FastAPI、Flask、Node.js 等技术构建卓越的 Web 应用程序。换句话说,我们可以将工作的重心放在构建用户实际需要的工具和软件上,毕竟对用户而言,这些才是真正的价值所在。

MySQL、PostgreSQL、Redis 和 Django

很长一段时间以来,配合 Django 使用最广泛的数据库都是 PostgreSQL,这在很大程度上可能因为只能在 Postgres 中使用 JSONField。然而随着 Django 3.2 + 和 MySQL 5.7.8 + 的推出,JSONField 也已经可用于 MySQL 了。

这一点为何重要?

在处理用户生成的内容或存储来自其他 API 服务的数据时,通常需要存储非结构化的数据,例如 JSON。一起来看看具体是怎么做的:

from django.db import models
class Pet(models.Model):
 name = models.CharField(max_length=200)
 data = models.JSONField(null=True)
 def __str__(self):
 return self.name

我们可能想要存储与Pet 有关的如下数据:

pet1 = {
 "name": "Bruno",
 "type": "Rat",
 "nickname": "We don't talk about it",
 "age": 2,
 "age_interval": "months"
}
pet2 = {
 "name": "Tom",
 "type": "Cat",
 "breed": "Mixed"
 "age": 4,
 "age_interval: "years",
 "favorite_food": [{"brand": "Acme", "flavor": "Tuna" }]
}
pet3 = {
 "name": "Stewey",
 "type": "Dog",
 "breed": "unknown"
 "age": 34,
 "age_interval: "dog years",
 "nickname": "Football"
}

从上述数据中我们可以知道什么时候可能需要一个 JSONField。我们可以存储所有宠物的名字(使用 name 键)并将其他信息存储在 JSONField 中。JSONField 最酷的地方在于,可以像其他标准 Django 字段那样查询,哪怕它们使用了不同的 Schema。

Django 开发者之间一直在争论要使用哪种数据库:MySQL 或是 PostgreSQL。以前,很多人会坚持选择 PostgreSQL,因为 JSONField 只能在 PostgreSQL 中使用,但现在情况不同了。因此我们完全可以任选一个并一直使用,直到所选数据库已经无法满足自己的需求。

但为何又要使用 Redis?

Redis 是一种速度惊人的内存中数据存储技术,因此通常被用作临时数据库(稍后将详细介绍这一点)、缓存服务以及 / 或消息队列。之所以将其称之为 临时数据库 是因为该技术将数据保存在内存中,内存通常比磁盘存储更贵,因此将数据长期存储在内存中往往并不是可行的做法。

本例中的 Redis 和 Django 主要用于缓存和队列。

缓存:假设用户需要频繁访问某几个网页,我们希望能尽可能快速地向用户展示这些页面的数据。如果配合 Django 使用 Redis 作为缓存系统,就可以轻松实现这一点。这些页面上的数据可能是从一个 SQL 数据库中渲染出来的,但 Redis 依然可以将渲染出的数据存储在缓存中。换句话说,将 Redis 与 SQL 配合使用通常可以加快响应速度,同时减少对 SQL 数据库发出的查询数量。

队列:Redis 的另一个流行用例是将长时间运行的任务分载(Offload)到另一个进程(这通常可借助一个名为 Celery 的 Python 包实现)。如果需要这样做,即可使用 Redis 作为队列,保存需要在另一个时间完成的任务。

举例来说,如果有用户需要一份有关过去五年来所有交易的报表,软件可能需要花费几小时才能生成这样的报表。很明显,没人愿意盯着计算机等待数小时之久。因此我们可以把这种请求从用户那里分载到一个 Redis 队列中。一旦放入 Redis,就可以运行工作进程(例如将 Celery 与 Django 配合使用)来生成报表。报表创建完成后,无论该过程花费了多长时间,用户都能收到通知。和其他通知一样,这种通知也可以通过 Redis 队列与 Celery/Django 工作进程配合实现。

上述内容都是为了说明:Redis 和 MySQL 可以实现非常美妙的互补。我们可以通过 Linode Marketplace 部署自行管理的 Redis 数据库服务器。

对象存储

我们推荐的最后一个与数据有关的托管服务是 Linode Object Storage。Object Storage 负责保存我们需要存储的所有其他类型的数据,毕竟肯定没人会希望将一个视频文件的所有数据都存储在 MySQL 中。数据库可以只用来存储与视频有关的元数据,而视频文件本身,可以存储在 Object Storage 中。

我们可以使用对象存储服务来存储类似下面这些数据:

总结

按照本文推荐的思路,任何开发者都可以在自己的 Web 应用程序项目中充分发挥托管服务的力量。Django 是一种在 SQL 数据库基础上构建 Web 应用的出色解决方案,但它并非唯一。如果希望深入探寻 SQL 和 SQL 服务器的内部原理,我们认为有必要通过不断的研究来了解到底有多少成功的应用程序在使用 Django 来处理各种工作。

将 Django 与 Linode 的托管 MySQL 配合使用,可以获得包括但不限于下面列举的这些好处:

这篇文章的内容感觉还行吧?有没有想要立即在 Linode 平台上亲自尝试一下?别忘了,现在注册可以免费获得价值 100 美元的使用额度,快点自己动手体验本文介绍的功能和服务吧↓↓↓

出海云服务,选择Akamai Linode!

欢迎关注 Akamai,我们将定期分享各种实用技巧,帮助大家了解如何通过现代方法在 Linode 上部署 Django 应用程序,如何更好地使用托管的 MySQL 数据库,如何通过 GitHub Actions 实现 CI/CD,以及与 Terraform、Ansible 等技术有关的各类实用技巧。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯