泛谈django开发小站 | 第19期
之前发的帖子基本都是具体的技术操作,但对技术而言,零碎的操作虽然必不可少,但也并不是全部,总得需要一些抽象的务虚的思考才能连成串,最终变成自己的体会心得。因此开了一个新的话题--“经验之谈”,主要是聊一聊心得体会。最近使用Django开发了一个小站,并在服务器上部署完成。虽然总体下来并没有技术难点和挑战,但是其中有一些开发的经验值得分享,对于打算使用django开发的朋友而言可以增加整体把握的能力,对于没有真实部署过网站的朋友而言也可算是一次新鲜的预演,对于Django开发的爱好者而言提供一个讨论交流的契机。本文将分三个部分来讨论django小站的部署,分别是:django四大组件、数据库和网站部署。
1. django四大组件
绝大多数的网站都是小站,这里的小站是指流量比较小,通常用户规模在10万以下。对于这种小站开发,基本上尽量使用简单廉价的技术。django作为python的一个免费开源的第三方库,功能强大并且全面,网上教程丰富,部署简单,这就是我们选择django的原因。由于流量较小,因此网站的开发重点并不在于处理高并发,毕竟只有大公司、大流量的网络应用才有能力划拨专人负责并发性能的提升。Django开发小站的最主要工作量就在路由、视图、模型和模版这四个方面。基本上只要有能力把握住这四个方面就有能力开发完成功能完备的小型网站。
(1). 路由 url
路由就是url访问链接与响应程序之间的映射关系。在一个django项目(Project)中可以有多个django应用(App),每个dango应用都可以设置自己的路由方式,然后在总的路由表中引用即可。路由中的url与响应函数的设置是非常直观的,而每个路由都可以有一个名字,这一点对于初学者而言并不是十分清楚的。通常我们设置了一个路由之后,除了在浏览器中输入url这种使用方式之外,还有在其他地方引用这些路由,比如页面重定向,以及在html中设置跳转链接等等。如果在开发之初没有使用路由名字来实现这些功能,而代之以绝对链接,那么在开发后期需要调整路由的时候,将面临很大的麻烦,这种麻烦不仅仅是工作量上的,而且是健壮性上的。我们知道python是动态语言,只有运行到错误语句时才会报错。而大规模修改路由很可能存在疏漏,测试用例一旦没有覆盖,将在实际的生产中出现程序崩溃这种严重后果。我们没有任何理由假设自己全面全能而没有疏漏,而采用路由名字是最安全且专业的做法。
(2). 视图 view
视图就是响应url调用的函数。通常对于前端的控制、策略以及html页面分发都在视图中实现。控制和策略因需求而异,这里不做讨论。html页面分发通常分为两部分:模版加载和模版渲染。视图渲染html模版的最终结果将呈现给用户,除了信息展示之外,还有一些需要用户填写的表单。django封装了十分好用的forms模块提供表单支持。一般使用forms.Form的派生类完成表单字段的定义以及数据合法性的清洗。一般程序开发讲究一个基本原则是低耦合,也就是模块之间的关联尽量简单。使用表单的时候也应当尽量遵守这个原则,比如表单的字段和数据合法性都在表单类定义的时候完成,而在视图中只是调用通用的接口获取数据,然后直接使用。
很多朋友可能会见过有的人使用函数视图,即使用函数作为响应url调用的方法,有的人使用类视图,即使用类封装url调用的响应。初学者可能会认为类视图的方式更加高级,但是实际使用而言并不必拘泥于此,如果有大量重复代码,从代码重用性角度而言应当使用类视图,而普通的小项目也没有太多的重复代码的话,还是使用函数视图更加简单。
(3). 模型 model
网站需要利用数据库来实现记忆的功能,而django提供了模型来对数据库的操作进行封装。开发者使用django模型操作数据库与sql语句操作的感受简直是云泥之别。使用models.Model的派生类来定义数据库中的数据表,使用暴露的一组接口来进行数据表的增删改查,同时支持各类型外键的正向和反向查询。通常建立数据表之后,使用admin.Admin派生类来实现后台管理数据表。django的中Admin是可以高度定制化的,也就是说可以通过设置一些参数使得后台管理的功能更加完善而且美观,比如数据搜索以及多对多的外键设置的界面等等。
事实上,django的模型不仅仅可以在django网站中使用,还可以使用standalone的方式在本地的小应用中使用,这避免了开发人员拼接大量sql语句的麻烦。如果需要在本地python应用中实现比较复杂的记忆功能,那么django模型是一个不错的选择。
(4). 模版 template
模版是具有一定通用性的html文件。在一个网站的前端中,有很多的内容是重复的,比如导航栏,如果每个页面都写一遍不仅麻烦,而且可能造成不一致。这时如果使用模版中的include语句就能在很大程度上提高重用性,并保证一致性。
通常我们需要将数据库的查询结果或者后端的处理结果显示在前端上,模版的一个很重要的作用就是满足这种需求。此外,django还提供了过滤器的机制,实现在模版渲染时调用一些函数处理需要呈现的数据。这些为搭建一个简易的前端提供了便捷,在bootstrap的加持下,即使并非专业的前端工程师,也能设计出看起来还不错的前端系统。
2. 数据库
数据库是后端中的一个核心组件,不过使用django开发小站的开发者并不需要对数据库了解太多。很可能有一批数据库的爱好者正在赶来抨击我的路上,不过这一观点并不改变。django已经为数据库提供了非常完备的功能,一般开发小站所使用的数据表的结构并不复杂,数据量也并不大,完全可以在django模型的框架下完成。另外使用django内置的两个命令makemigrations和migrate来进行模型修改的记录和数据表定义的更新,使用dumpdata和loaddata来进行数据库数据的导出和导入。不过,关于数据库还有两个麻烦点还是需要简单讨论一下:数据库的选择和数据库的迁移。
(1). 数据库的选择
django默认配置的数据库是sqlite3,这个数据库是存储在项目根目录下的一个文件中,特点是简单方便,缺点是并发写入的性能比较差。一般而言,网站项目是需要用户写入一些数据的,而多用户写入时天然存在对并发性能的要求。只是说在小站中这种要求并不太高,但是sqlite3还是无法满足的。如果确定自己的网站只有极少数管理员写入,而读取的并发量也不太大,可以考虑使用sqlite3,不过这种情况极其少见。通常我们会选择一个第三方的数据库服务,比如mysql或者oracle。从成本角度来看,还是mysql比较划算,而且以mysql的能力而言,处理中等流量的网站都是可以胜任的,对于小站而言就绰绰有余了。在一些Linux的发行版中,已经默认了mariadb作为mysql的源,因此在安装mysql的时候直接安装的是mariadb,不过这两者基本一致,所以影响不大。
(2). 数据库的迁移
如果开发时使用的数据库和部署时使用的数据库不一样,那么就需要迁移数据库,不过这并不是一个简单的事情。有的朋友可能会说,直接使用dumpdata命令导出,然后使用loaddata导入到新的数据库不就可以了吗?这里的回答只能是大概率不行。如果只定义了简单的几个表,这种迁移的操作还是有可能成功的,如果一旦涉及到一些外键,那么迁移的过程应该是命途多舛。这里提供一个导出指令的调用方式仅供参考, python3 manage.py dumpdata appname --exclude=contenttypes --exclude=auth.Permission --exclude=admin.logentry --exclude=sessions.session --indent 4 > initial_data.json 除此之外还有一些麻烦,比如sqlite3与mysql容错机制不一致,sqlite3与mysql对主键的默认操作不一致等等。因此,最好在一开始就选定所使用的数据库。
3. 网站部署
网站开发完成之后,就可以进行部署。部署需要的设备是一台具有公网IP的计算机,通常我们会租用VPS。当然还可以使用内网穿透的方式,将网站部署在本地的计算机上,不过并不常见,这里还是以VPS上的部署来进行讨论。我们在开发过程中已经使用了django内置的服务器,不过在部署时这个内置的服务器无法满足需求,特别是在高并发访问时捉襟见肘。目前常用的搭配是nginx+uwsgi来部署django网站。由于安全性的考虑以及目前网站协议使用HTTPS的潮流,我们需要为网站域名申请证书,以拥抱https协议。最后网站部署完成之后,总是需要一些定时任务来检查数据库所处的状态,从而更新另一些数据的状态。下面就对这三个方便稍加讨论。
(1). nginx+uwsgi
nginx直接使用系统的安装指令进行安装,uwsgi可以使用pip指令安装。uwsgi是实现wsgi协议的工具,事实上,直接用uwsgi就可以构建网站服务,不过uwsgi对静态文件的分发性能不如nginx,因此还需要使用两者配合。首先可以使用uwsgi工具直接启动网站服务,并可以在浏览器访问,测试没问题之后,就可以使用ini配置文件后台运行uwsgi的服务了。uwsgi与nginx之间的通信使用sock完成,在ngnix的配置文件中指明sock通信文件所在路径和网站项目所在路径即可。一个可以正常运行的网站就搭建完成,不过这个网站还是http的。
(2). 证书
如果希望使用https来提供网站服务,则需要申请SSL证书。证书分为收费和不收费两种,可想而知,免费的自然就粗糙些,使用起来麻烦些。这里提供一个免费生成证书的工具https://dl.eff.org/certbot-auto, 使用指令./certbot-auto certonly --standalone --email ${email} -d ${domain}就可以创建证书了。不过这个证书的有效期只有三个月,三个月后可以使用certbot-auto renew指令来进行续签。如果证书创建完成,会在命令行的提示中告知存储路径,根据该路径设置nginx配置中的相关字段即可。这里只是一个总体务虚的经验之谈,因此涉及具体配置的地方并未给出例子。网上这种配置实在太多,随便搜索就一大把。
(3). 定时任务
网站部署的最后一步是启动定时任务。代理定时任务的服务有很多,不过在Linux系统中,最简单方便的还是crontab。虽然大家一看就会,不过关于crontab配置定时任务还是有个麻烦的地方--环境变量。很多朋友可能使用crontab设置好定时任务之后发现无论如何都不执行,没有经验的朋友可能就此抓瞎,以为crontab功能存在缺陷,但实际上是环境变量的问题。如果所启动的定时任务为python程序,那么在python程序中的操作都需要使用绝对路径。如果使用shell脚本,可以在脚本中加载环境变量。还有一个办法是把环境变量重新写到一个shell文件中,然后在crontab中先运行这个脚本,再运行对应的定时任务。可能有朋友会说,直接运行/etc/profile不是更方便吗?事实上,我在Debian9的系统上测试发现不行,原因是crontab以非交互式的方式运行,而/etc/profile的开头有检查导致运行失败。如果大家怀疑可能环境变量存在问题可以重定向命令的输出到文件中,然后查看环境变量与预想是否一致即可。
关于django开发小站就讨论这么多,这篇文章总体务虚,可能大家感觉并不是太有干货,但是就整体把握一个小站开发而言,会有提纲挈领的作用。特别是对其中提到的一些问题提前规避,能够极大提升开发效率。熟练使用django之后,基本两周就能开发出一个功能完备的小站,服务数万用户基本没有太大问题。
欢迎对python和人工智能感兴趣的朋友加入微信群讨论和交流: