关于开始使用 Django 的一些笔记
你好!我最喜欢做的事情之一,就是开始学习一种我以前从未尝试过、但已经存在了 20 多年的老派无聊技术。当我将来可能遇到的每个问题都已经被解决过 1000 次,而我只需要轻松地把事情做成时,感觉真的非常好。
很久以来,我一直觉得学习 Rails、Django 或 Laravel 这样的热门 Web 框架会很酷,但始终没能真正做到。不过几个月前,我开始学习 Django,用它来做一个网站。到目前为止我很喜欢它,所以这里简单记下几点!
比 Rails 少一些魔法
2020 年我花了一些时间尝试学习 Rails。虽然它很酷,而且我也确实很想喜欢上 Rails(Ruby 社区很棒!),但我发现,如果把 Rails 项目放上几个月不管,之后再回来时,我很难记起该怎么做任何事情。因为,举例来说,如果你的 routes.rb 中写着 resources :topics,单看这一行并不能告诉你 topics 的路由配置在哪里;你得记住这个约定,或者查一下。
对我来说,能够把一个项目丢上几个月甚至几年,然后再回来继续做非常重要(我所有的项目都是这样运作的!)。而 Django 让我觉得更容易上手,因为它的东西更加明确。
在我的这个小型 Django 项目里,除了设置文件之外,感觉主要就只有 5 个文件:urls.py、models.py、views.py、admin.py 和 tests.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 张表:zines、zine_products、products、order_products 和 orders。为了让它正常工作,我只需要告诉 Django:“orders”和“products”之间有一个 ManyToManyField 关联,另外“zines”和“products”之间也有一个 ManyToManyField 关联。这样它就知道该如何连接 zines、orders 和 products 了。
我当然可以自己写出这个查询,但写 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 的哪个功能吧!)
随机一篇博客