Some notes on starting to use Django

Julia Evans

关于开始使用 Django 的一些笔记

你好!我最喜欢做的事情之一,就是开始学习一种我以前从未尝试过、但已经存在了 20 多年的老派无聊技术。当我将来可能遇到的每个问题都已经被解决过 1000 次,而我只需要轻松地把事情做成时,感觉真的非常好。

很久以来,我一直觉得学习 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 模板),通常只要查看这几个文件中的某一个,就能看到明确的引用。

内置的 admin

这个项目需要一个 admin 界面,用来手动编辑或查看数据库中的部分数据。Django 内置了一个非常好用的 admin 界面,只需要写一点代码就能定制。

比如,下面是我的一个 admin 类的部分代码,它设置了“list”视图中要显示哪些字段、根据哪个字段搜索,以及默认按什么顺序排列:

@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:“orders”和“products”之间有一个 ManyToManyField 关联,另外“zines”和“products”之间也有一个 ManyToManyField 关联。这样它就知道该如何连接 zinesordersproducts 了。

我当然可以自己写出这个查询,但写 product__order__email_hash 要少打很多字,读起来也容易得多。说实话,我觉得自己可能得花一会儿才能弄清楚如何构造这个查询(它除了这些连接之外还需要做其他几件事)。

我完全不担心 ORM 生成的查询性能,所以目前对 ORM 相当兴奋,不过我相信最终还是会找到一些让自己烦恼的地方。

自动 migrations(数据库迁移)!

ORM 的另一个优点就是 migrations!

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

我想,如果愿意的话,我应该可以编辑这些脚本;但到目前为止,我一直直接运行生成的脚本,没有做任何修改,而且一切都进行得非常顺利。真的感觉像魔法一样。

我逐渐意识到,现在对我来说,能够轻松完成迁移非常重要,因为随着我摸索数据模型应该如何设计,我经常会修改它。

我喜欢这些文档

我以前有个坏习惯,就是从来不读文档,但到目前为止,我真的很喜欢 Django 文档中已经读过的那些部分。这并非偶然:Jacob Kaplan-Moss(雅各布·卡普兰-莫斯)曾在 2011 年的 PyCon 演讲中介绍过 Django 的文档文化。

例如,模型入门一节列出了使用 ORM 时可能需要设置的最重要、最常见的字段。

使用 sqlite

之前尝试运维 Postgres 时有过一段糟糕的经历,而且完全搞不明白发生了什么,于是我决定改用 SQLite 来运行自己的所有小型网站。这样顺利多了。我还很喜欢只要执行一个 VACUUM INTO,再复制生成的那个文件,就能完成备份。

我一直按照这份指南在生产环境中使用 SQLite 和 Django。

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

内置的 email(以及更多功能)

Django 似乎非常“开箱即用”,这一点我很喜欢——如果我需要 CSRF 防护、Content-Security-Policy,或者想发送 email,这些全都内置了!

比如,我希望在开发模式下把 Django 发送的 email 保存到文件中(这样就不会把真正的邮件发给真正的人),只需要做一点配置。

我只要把下面这些内容放进 settings/dev.py

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

然后在 settings/production.py 中这样设置生产环境的 email:

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 文件还是感觉内容很多

我还是有点被 settings.py 文件吓到:Django 的设置系统通过在一个文件中设置一堆全局变量来工作,而我会有点担心……万一我把其中某个变量的名字拼错了怎么办?我怎么会知道?比如,我把 WSGI_APPLICATOIN = "config.wsgi.application" 写成这样,而不是 WSGI_APPLICATION,会怎样?

我想,我已经习惯了让 Python language server 在我拼错时提醒我,所以现在无法依赖 language server 的支持,会让我有点不知所措。

暂时就这些!

以前我还没有真正成功地在项目中使用过实际的 Web 框架(目前我的网站几乎都是单个 Go 二进制文件或静态网站),所以我很想看看接下来会怎么样!

还有很多东西等着我学习。我还没有真正开始研究 Django 的表单验证工具或身份验证系统。

感谢 Marco Rogers(马可·罗杰斯)说服我给 ORM 一个机会。

(我们还在继续试验通过 Mastodon 评论的系统!这里是 Mastodon 上的评论!告诉我你最喜欢 Django 的哪个功能吧!)

原文由 Julia Evans 发布

本文章由 openai/gpt-5.6-luna 进行翻译