Django搭建网络相册:数据存储

378 views, 2021/08/05 updated   Go to Comments

上一章的 Django 请求响应流程中,我们简单地返回了一个字符串供前端显示。但是在实际情况下,总会有大量的动态数据需要储存和使用,比如文章的标题和正文、用户的名称和密码等。

存储这些数据需要专门的地方,被称为数据库。本章就来了解下如何在 Django 中使用数据库。

数据库与模型

数据库是存储信息的场所。数据库由多个数据表构成。

啥意思?举个栗子,三年级二班中同学名册就是数据表。有的名册记录每位同学的考试成绩、有的记录身高体重、还有的记录兴趣爱好...所有的这些名册都放在老师的柜子里,这个柜子就是“数据库”了。

默认情况下,数据库就是db.sqlite3这个文件了。

在网站上线后你可能想换别的数据库,不过目前还不需要讨论这个内容。

操作数据库使用的是古老的 SQL 语句,它是完全不同于 Python 的另一种语言,这对新手来说无疑是困难的。

幸运的是,在 Django 里写小型 Web 应用并不需要你直接去操作数据库。你只需要用 Python 语言定义好模型,而模型会自动生成操作数据库所必要的一切。

这叫对象关系映射Object Relational Mapping,简称ORM),用于实现编程语言里不同类型系统的数据之间的转换。

光讲理论有点枯燥,接下来通过实践理解。

编写模型

Photo App 中的 models.py 就是编写模型的地方。

将其修改如下:

# /photo/models.py

from django.db import models
from django.utils.timezone import now

class Photo(models.Model):
    image   = models.ImageField(upload_to='photo/%Y%m%d/')
    created = models.DateTimeField(default=now)

    def __str__(self):
        return self.image.name

继承自 models.Model 的对象被称为模型类,它对应了数据库中的数据表。模型类中可以定义很多字段,字段对应数据表中的不同信息。

比如名册,里面每个同学都有姓名、年龄,在数据库中就是姓名字段、年龄字段等。

Photo 模型中仅有两个字段。

ImageField 字段用于存储图片信息。通常来说,字段中会存储对应数据,比如 CharField 会将字符数据保存在数据库中。但 ImageField 有点特殊,因为图片作为一种文件,直接保存在硬盘中就足够了,并不需要真正放进数据库中。因此 ImageField 实际上只在数据库中保存了图片的名称、存储路径、索引等元数据,真正的图片文件被保存在 upload_to 参数所指定的路径中。

'photo/%Y%m%d/' 是动态格式化当前日期的特殊书写方式。比如今天是2021年8月5日,那么图片将被保存在项目路径下的 /photo/20210805/ 文件夹中。

另外一个 DateTimeField 用于记录图片创建的时间,默认值为当前时间。

方法 __str__ 用于美化模型在后台、命令行中的输出信息。

接下来要修改 /album/settings.py 文件,这是 Django 的全局配置文件:

# /album/settings.py

...

INSTALLED_APPS = [
    'django.contrib.admin',
    '...

    # 注册App
    'photo',
]

...

# 指定媒体文件路径
MEDIA_URL  = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'

photo 添加到 INSTALLED_APPS 列表中,让 Django 程序加载这个自定义的 App。

后续进行模型迁移时,程序会在此列表中进行搜索。

由于图片是媒体文件,它并不直接保存在数据库中,因此要增加 MEDIA_URLMEDIA_ROOT 配置,指定这些图片上传的路径位置。

此外,媒体文件表现在前端中同样也是单独的 url 路径。因此要在根路由文件 /album/urls.py 添加对其的路径支持:

# /album/urls.py

...

from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    ...
]  + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

至此模型基本就写好了。

只有在开发阶段时,即 settings.py 中的 DEBUG = True 时,服务器才会处理图片或 .js 这类静态文件。当 DEBUG = True 时,Django 服务器将拒绝处理静态文件(由于效率低下),此时需要将其交给 nginx 进行处理。后续部署的章节将会继续讨论。

接下来进行数据迁移。

数据迁移

数据迁移这个词听起来很玄乎,其实它有点类似于将刚才写的模型同步到数据库里。要记得数据库和 Python 是完全不同的东西,你在 Python 里写的模型长啥样,数据库并不知道。因此需要数据迁移这个步骤,Django 框架将在幕后自动为你处理好 Python 对象和数据库数据之间的对应关系。

张三(Python)有一本名册(模型类),拿给了李四(数据库)。李四将名册的结构(需要记录哪些信息)原封不动抄到自己的名册中(数据迁移)。

由于 ImageField 的数据迁移依赖 Pillow 库,因此首先安装它:(一定要记得在虚拟环境中!)

(env)> pip install Pillow==8.3.1 -i https://pypi.tuna.tsinghua.edu.cn/simple
...
Successfully installed Pillow-8.3.1

接着输入指令创建迁移文件:

(env)> python manage.py makemigrations
# 以下为输出
Migrations for 'photo':
  photo\migrations\0001_initial.py
    - Create model Photo

成功后执行迁移:

(env)> python manage.py migrate
# 以下为输出
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, photo, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  ...
  Applying photo.0001_initial... OK
  Applying sessions.0001_initial... OK

没报错就表示迁移成功了。

接下来我们存储些数据看看效果。

后台操作

Django 开发之所以高效,原因之一就是自带很多通用功能的默认实现,比如后台管理功能。

首先在命令行里创建管理员账号:

(env)> python manage.py createsuperuser

Username (leave blank to use 'dusai'): dusai
Email address:
Password:
Password (again):
Superuser created successfully.

注意在命令行里填写密码是不会显示任何字符的。

接着还需要将 Photo 模型注册到后台中。修改 /photo/admin.py 文件如下:

# /photo/admin.py

from django.contrib import admin
from photo.models import Photo

admin.site.register(Photo)

这就Ok了。

重新启动服务器,输入 127.0.0.1:8000/admin 路径:

出现了管理员登录页面。

输入刚才的账号密码登录后台:

可以看到后台中已经有了 Photo 的管理入口。

点击 Add 添加新的图片数据:

随便选择一张本地图片,并点击 Save

保存好之后,就可以在后台中看到已经上传的图片信息了。

接着到 /media 路径查看,图片文件确实也岁月静好的躺在那里:

总结

Django 的 ORM 模型系统给刚入门的同学非常多的便利。有可能你听都没听过操作数据库的 SQL 语言,却感受不到任何痛苦,因为模型的存在让你以 Python 的方式进行建库建表、增删改查等常规操作。但 ORM 的缺点就是处理复杂的查询语句会比较费劲,到那时就是你恶补数据库原生命令的时候了。

Django 开发的三剑客:模型、视图、模板,前面两个已经见识过了。下一章拜会最后一位:模板,也聊聊 MTV 模式。

点赞或吐槽?到评论区和我交流!




本文作者: 杜赛
发布时间: 2021年08月05日 - 11:24
最后更新: 2021年08月05日 - 11:24
转载请保留原文链接及作者
本站使用 Github 评论后端。鉴于国内复杂的网络环境,如遇评论无法加载、发表等问题,请尝试刷新页面,或更换上网姿势。