起步
相比 fastapi、flask 等 http 框架,django 一直被 python 程序员认为“重”。“重”有很多理解方式,我至少认为它不是在指责 django 大而全——由于自己多才多艺而被嫌弃,django 岂不是很冤?!所以我理解的、普遍意义的“重”是:django 总要给我提供我不需要的东西。
在我看来,django-admin startproject
,django-admin startapp
绝对是万恶之源。命令末尾一回车,我需要的不需要的都来了,项目的目录结构也被死死钉住。所以长期以来我对 django 绝无任何好感。直到一次在推特上表达心声,有个大佬对我的言论充满鄙夷,一来二去的交锋,最后被他推荐去看《Lightweight Django》。
我一直以来认为用 django 写 demo 是挺烦人的,但《Lightweight Django》的作者却说:不用麻烦了。
如果是 flask
flask 长期以来作为 django 的竞争对手,并以“轻”著称,那么先来看看 flask 如何启动一个 web 服务。
from flask import Flask
app = Flask(__name__)
@app.route("/")
def index():
return "hello world"
if __name__ == "__main__":
app.run(host="127.0.0.1", port=8000, debug=True)
很简洁是不是?但这只是“缩写”而已。一旦我们要写一个正常一点的项目,就算是规模小一些,用“缩写”就不够用了。比方说响应头的 header 设置,比方说路由的模块划分。所以实际项目中,flask 的代码组织结构大概率呈现如下方式:
import os
# 环境变量
debug = os.environ.get("debug", "on") == "on"
from flask import Flask, make_response
app = Flask(__name__)
# 配置信息
app.config.update(
debug=debug,
)
# 视图函数
def index():
response = make_response("hello world")
return response
# 注册路由
app.add_url_rule("/", None, index)
if __name__ == "__main__":
# 启动程序
app.run(host="127.0.0.1", port=8000)
(注册路由不再用装饰器,仅仅是我个人爱好而已)
也就是说,一个 http 服务至少是需要配置信息,视图函数,注册路由三部分;为了能跟 uwsgi 通信,我们还需要 application,好巧不巧,app = Flask(__name__)
语句中的 app 就是那个我们要的 application;最后是启动服务的 app.run()
。
请记住这个结构,接下来我们就用 django 来实现。
轻量级 django
首先来完成视图函数,这稍微简单些:
from django.http import HttpResponse
def index(request):
response = HttpResponse("hello world")
return response
与 flask 稍稍不同,django 要求视图函数默认接收一个 request 参数。
接着是路由。django 中,路由的“注册”方式是静态的,因为它不是去注册,而是以配置的方式添加路由:
from django.conf.urls import url
# urlpatterns 是默认变量
urlpatterns = (
url("^$", index),
)
但是现在对 django 来说,它还找不到路由。django 是自己去注册路由,而你需要告诉它路由文件在哪儿。“告诉”这个动作需要在配置信息里弄。所以正好把 django 的配置信息方式说了。
import os
# 环境变量
debug = os.environ.get("debug", "on") == "on"
from django.conf import settings
settings.configure(
DEBUG=debug,
ROOT_URLCONF=__name__, # 告诉 django, 配置路由的文件在哪儿
)
现在完成了配置信息,视图函数,注册路由三部分,我们还需要通信的 application。
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
最后是启动服务。你有两种方式,一种是选择python xxx.py runserver
,另一种是python xxx.py
。为了对标 flask,这里就选择实现后者:
from django.core.management import execute_from_command_line
execute_from_command_line([__name__, "runserver"])
事实上,我们已经完成了一个轻量级的 django http 服务。完整代码如下:
import os
from django.http import HttpResponse
from django.conf.urls import url
from django.conf import settings
from django.core.wsgi import get_wsgi_application
# 环境变量
debug = os.environ.get("debug", "on") == "on"
settings.configure(
DEBUG=debug,
ROOT_URLCONF=__name__,
)
# 视图函数
def index(request):
response = HttpResponse("hello world")
return response
# 注册路由
urlpatterns = (
url("^$", index),
)
application = get_wsgi_application()
if __name__ == "__main__":
# 启动程序
from django.core.management import execute_from_command_line
execute_from_command_line([__name__, "runserver"])
总结
认真说起来,轻量级的 django 还是比 flask 麻烦一点点,尤其导包太多(不失尴尬的微笑)。但通过学习启动轻量级 django,大致明白了 django-admin startproject
生成的内容都有什么用,也可以自己掌握代码的目录结构啦,以后就不会糊里糊涂觉得 django “重” 了。
参考
- 《Lightweight Django - The World’s Smallest Django Project》
还不快抢沙发