Some notes on starting to use Django

Julia Evans

开始使用 Django 的一些笔记

原文由 Julia Evans 发布,订阅该博客

你好!我最喜欢的事情之一,就是开始学习一项自己从没尝试过、但已经存在了 20 多年的“陈旧无聊的技术”。当我遇到的每一个问题都已经被别人解决过上千次,而我只需要轻松地把事情搞定时,感觉真的很好。

我一直觉得学一个像 Rails、Django 或 Laravel 这样流行的 Web 框架会很酷,但始终没能真正付诸行动。几个月前,为了做一个网站,我开始学习 Django,到目前为止还挺喜欢的,这里是一些随手记下的笔记!

比 Rails 少一些“魔法”

2020 年我花了一些时间尝试学习 Rails,虽然它很酷,我也真的很想喜欢上 Rails(Ruby 社区非常棒!),但我发现如果把 Rails 项目搁置几个月再回来,就很难想起该怎么干活了,因为(举个例子)如果你的 routes.rb 里写着 resources :topics,光看这一行根本看不出 topics 的路由是在哪里配置的,你得记住或者去查它的约定。

能够把一个项目丢在一边几个月甚至几年,之后再回来继续做,对我来说非常重要(我所有的项目都是这样的!),而 Django 对我来说感觉更轻松,因为它的写法更显式。

在我这个小小的 Django 项目里,感觉除了配置文件之外,就只有 5 个主要文件:urls.pymodels.pyviews.pyadmin.pytests.py,如果我想知道别的东西(比如 HTML 模板)在哪里,通常都能在其中某个文件里找到显式的引用。

自带的管理后台

在这个项目里,我想要一个管理界面来手动编辑或查看数据库里的一些数据。Django 自带了一个非常好用的管理后台,只需要写一点点代码就能进行定制。

比如,下面是我的其中一个 admin 类的一部分,它设置了在“列表”视图中显示哪些字段、按哪个字段搜索,以及默认的排序方式。

@admin.register(Zine)
class ZineAdmin(admin.ModelAdmin):
    list_display = ["name", "publication_date", "free", "slug", "image_preview"]
    search_fields = ["name", "slug"]
    readonly_fields = ["image_preview"]
    ordering = ["-publication_date"]

有 ORM 还挺有意思的

过去我的态度是“ORM?谁需要那玩意儿?我自己写 SQL 就行!”不过到目前为止,我还挺喜欢 Django 的 ORM 的,我觉得 Django 用 __ 来表示 JOIN 的做法很酷,就像这样:

Zine.objects
    .exclude(product__order__email_hash=email_hash)

这个查询涉及 5 张表:zineszine_productsproductsorder_productsorders。要让它跑起来,我只需要在 Django 里声明有一个 ManyToManyField 关联了“orders”和“products”,还有另一个 ManyToManyField 关联了“zines”和“products”,这样它就知道该如何连接 zinesordersproducts 了。

我当然可以自己写出那个查询,但写 product__order__email_hash 要少打很多字,读起来也感觉容易得多,说实话,要让我自己去拼出那个查询(除了那几个 JOIN 之外还要做一些别的事情),恐怕还得花上一点时间。

我完全不担心 ORM 生成的查询的性能,所以目前对 ORM 还挺兴奋的,不过我相信以后肯定也会遇到让人头疼的地方。

自动迁移!

ORM 另一个很棒的地方就是迁移!

如果我在 models.py 里添加、删除或修改一个字段,Django 会自动生成一个类似 migrations/0006_delete_imageblob.py 的迁移脚本。

我想如果需要的话,我也可以去编辑这些脚本,但到目前为止,我都是直接原样运行生成的脚本,效果一直很好。真的感觉像魔法一样。

我意识到,能够轻松地做迁移对现在的我来说很重要,因为在摸索数据模型该怎么设计的过程中,我改动得相当频繁。

我喜欢它的文档

我以前有个坏习惯就是从不看文档,但到目前为止,我读过的 Django 文档部分都让我非常喜欢。这并非偶然:Jacob Kaplan-Moss 在 PyCon 2011 上有一个演讲,专门讲了 Django 的文档文化。

比如,模型介绍里就列出了使用 ORM 时你可能想要设置的最重要常用字段。

使用 SQLite

在尝试运维 Postgres 却搞不清状况的糟糕经历之后,我决定把我所有的小网站都改用 SQLite 来跑。效果好多了,而且我特别喜欢只要执行一下 VACUUM INTO 然后复制生成的单个文件就能完成备份。

我在生产环境中使用 Django + SQLite 时,一直是按照这份指南来操作的。

我觉得应该没问题,因为我预计这个网站每天最多也就几百次写入,远比Mess with DNS 少得多,而后者写入量大得多却也一直运行良好(不过它的写入分散在 3 个不同的 SQLite 数据库里)。

内置的邮件功能(以及更多)

Django 似乎非常“开箱即用”,这点我很喜欢——无论是想要 CSRF 防护,还是 Content-Security-Policy,或是想发邮件,全都内置好了!

比如,我想在开发模式下把 Django 发送的邮件保存到文件里(这样就不会给真人发送真实邮件了),只需要做一点点配置就行。

我只需要在 settings/dev.py 里加上这些:

EMAIL_BACKEND = "django.core.mail.backends.filebased.EmailBackend"
EMAIL_FILE_PATH = BASE_DIR / "emails"

然后在 settings/production.py 里这样配置生产环境的邮件

EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = "smtp.whatever.com"
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = "xxxx"
EMAIL_HOST_PASSWORD = os.getenv('EMAIL_API_KEY')

这让我觉得,如果以后想要别的什么基础网站功能,Django 里很可能已经内置了简单易用的实现方式。

配置文件还是感觉有点多

我对 settings.py 文件还是有点发怵:Django 的配置系统是通过在一个文件里设置一堆全局变量来工作的,这让我有点焦虑……要是其中某个变量名打错了怎么办?我怎么知道?比如要是把 WSGI_APPLICATION 打成了 WSGI_APPLICATOIN = "config.wsgi.application" 呢?

大概是因为我已经习惯了让 Python 语言服务器来提醒我哪里打错了,所以现在没法依赖它的时候,就感觉有点无所适从。

就先写到这里!

我以前还没有真正成功地在项目中使用过 Web 框架(目前我几乎所有的网站要么是单个 Go 二进制文件,要么是静态站点),所以很期待看看这次会怎么样!

还有很多东西要学,比如 Django 的表单验证工具和认证系统,我都还没怎么接触过。

感谢 Marco Rogers 说服我给 ORM 一个机会。

(我们还在试验 Mastodon 上的评论系统!点此查看 Mastodon 上的评论!来告诉我你最喜欢的 Django 功能吧!)

本文章由 muse-spark-1.2-contributor 进行翻译

评论