django架站16课

django架站16课:从零到能用的架站真实记录

我写了个博客系统,用Django。架站不是架站教程里那种“hello world”级别的小demo,而是架站真正部署到服务器上、每天有人访问的架站那种。前后花了16天,架站每天下班后写2小时左右。架站这篇文章就是架站那16天的流水账,但我会把关键决策和踩过的架站坑都标出来。

第1天到第3天,架站我在搭模型。架站博客嘛,架站无非是架站文章、分类、架站标签。架站但真正动手时发现,光是“文章”这张表就够你纠结半天——要不要存摘要?要不要支持多作者?评论是单独应用还是内置?我最终选择了最朴素的方案:文章表只存标题、正文、发布时间、所属分类,标签用多对多关系。后来证明这个选择是对的,因为后面加功能时,简单的数据结构反而好扩展。

第4天碰到第一个坑。Django的时区设置,默认是UTC。我写了篇文章,发布时间显示比北京时间早8小时。查了半天文档,发现要改TIME_ZONE和USE_TZ两个配置项。但改了以后,数据库里已有的时间又全乱了。最后用了一个笨办法:把数据库里所有时间字段重新赋值一遍。这个坑让我明白,写任何web框架,第一时间就要把时区问题想清楚。

第5天到第7天在写模板。Django的模板语言很简单,但简单不等于好用。循环、判断、过滤器,这些基本够用。真正烦人的是页面布局——我用了Bootstrap,但嵌套的模板继承让CSS类名变得特别难管理。后来干脆把样式直接写死在每个模板的style块里,虽然不优雅,但至少改起来快。

第8天,我决定加个搜索功能。Django自带的icontains查询在数据量小时挺好使,但文章一多,查询速度肉眼可见地慢。我试了PostgreSQL的全文搜索,配置起来有些麻烦。最终还是回归到最简单的方式:在标题和正文里用icontains,再加个索引。够用了,毕竟我的博客撑死也就几百篇文章。

第9天到第11天,处理用户系统。Django自带的auth应用非常强大,注册、登录、登出、重置密码全都有。但我想要的是“只有我能写文章”,不需要开放注册。于是只用了admin后台,把is_staff设为True的账号才能登录。省事,而且安全——因为根本没有注册入口,想黑你得先知道我的用户名。

第12天遇到一个奇葩问题。部署到服务器后,上传的图片总是404。本地跑得好好的,服务器上就是不行。查了半天,发现是MEDIA_URL和STATIC_URL搞混了。Django默认把静态文件和媒体文件分开处理,但我在模板里用错了标签。修改后一切正常。这种低级错误,恰恰是新手最容易犯的。

第13天到第14天在折腾评论功能。一开始想用第三方库,比如django-comments,但发现它太笨重。最后还是自己写了个简单的评论模型,关联到文章,再写个表单。这让我意识到,很多看似“标准”的功能,自己动手做反而更可控。

第15天,我把代码从SQLite迁移到了MySQL。原因很简单——SQLite在并发访问时容易锁库。迁移过程比想象的顺利,只要把DATABASES配置改一下,再跑个migrate就行。但要注意,有些字段类型在两种数据库里表现不一样,比如布尔值在SQLite里存0和1,在MySQL里存true和false。还好我的数据量小,直接导出导入就解决了。

最后一天,第16天,我在给页面做速度优化。Django的ORM默认是懒加载的,查询关联对象时会生成很多条SQL。我用select_related和prefetch_related把查询次数从N+1降到了2次。页面加载时间从1.2秒降到了0.3秒。这个优化技巧,建议每个Django开发者都学一下。

现在这个博客已经跑了三个月,没出过什么大问题。回过头看,16天的时间分配大概是:模型设计3天,视图和模板4天,用户系统3天,部署和优化4天,剩下的时间在修各种小bug。Django确实是个好框架,它把很多繁琐的事情都帮你做了,但前提是你得理解它的设计思路——比如ORM的工作方式、模板的继承机制、中间件的调用顺序。这些东西不看文档直接上手,迟早会踩坑。

如果你也想用Django搭个站,我的建议是:别一开始就想做大而全的系统,先做个能跑的版本,然后每天加一个小功能。16天足够让你从零到一个能用的站点,关键是别在第一天就想着要完美。