注:很久之前就有了学习Django的想法,最近终于有机会做了一次尝试。由于Django的详细教程很多,我在这里就不再详述了,只是将整个开发流程以及自己在学习Django中的一些思考记录在此。

System:CentOS Linux release 7.2.1511 (Core)

Django: 1.10

Python: 2.7.5

推荐两个非常好的教程:

The Django Book(中文版):我自己一开始是参考这个教程学习的,非常有意思的是这个教程中有大量的评论,几乎每段都有,从10年开始一直到现在。虽然这本书比较老,有很多内容都过时了,但在这些评论中有讲解,有勘误和最新的实践,这些评论让整个学习过程变得非常有趣。我自己也留下了不少评论,哈哈。

被解放的姜戈:这是博客园的另一位博友Vamei(中文读作,挖煤)写的关于Django简介的系列文章,基本概念,简单的实践都有。

创建一个名为mysite的Django项目的命令:

$ django-admin startproject mysite

$ cd mysite

$ python manage.py startapp myApp  # 创建一个app,名称为myApp

一个刚创建的Django项目的目录结构

图1:django项目的基本结构

不是要点的要点


  1. 创建一个专门的用户,例如www-data:在后面部署Django的过程中,我遇到了自使用Linux以来,最多的权限问题。很大的原因是因为不同进程间需要通信,或相互访问,这就需要这些用户间都有某个文件的读写权限。例如两个进程都要访问同一个socket文件时,这两个进程的用户都要对该socket文件有读写权限。因此将所有这些进程都交给一个专门的用户来操作,可以避免很多权限问题。
  2. url是web开发的核心要素之一:在客户端,每一个url就是一个页面;从开发者来看,所有的开发都是围绕如何正确的路由这些url到正确的html文件来展开的。
  3. stackoverflow是一个很棒的网站,大部分的问题都可以在上面找到解决方案,如果没有找到答案,就提问吧,很快就可以得到回复。

概述


用户从浏览器访问一个django开发的页面,整个流程是这样的:

the web client <-> the web server <-> the socket <-> WSGI <-> Django

用户从浏览器访问一个url,该请求从用户发送到web server,web server通过socket(或者约定一个端口)与WSGI进行通信,再由WSGI将请求发给django。web server和WSGI都有很多种选择,常见的组合有Apache + mod_wsgi和nginx + uWSGI。我用的是nginx + uWSGI。下面先介绍几个名词。

web server

虽然每个网页服务器程序有很多不同,但有一些共同的特点:每一个网页服务器程序都需要从网络接受HTTP请求,然后提供HTTP回复给请求者。HTTP回复一般包含一个HTML文件,有时也可以包含纯文本文件、图像或其他类型的文件。

一般来说这些文件都存储在网页服务器的本地文件系统里,而URL和本地文件名都有一个阶级组织结构的,服务器会简单的把URL对照到本地文件系统中。当正确安装和设置好网页服务器软件,服务器管理员会从服务器软件放置文件的地方指定一个本地路径名为根目录。

web server是面对用户请求的第一道门,有些请求由web server自己处理,例如静态文件的访问等;还有一些请求则交给WSGI处理,如对动态页面的访问。

socket: 最近在学习《计算机网络》这门课,socket相关的内容在网络模型中属于传输层,位于网络层和应用层之间。主要用于实现进程间通讯。在这里主要是实现nginx和uWSGI两个不同进程之间的通讯。

WSGI:

Web服务器网关接口(Python Web Server Gateway Interface,缩写为WSGI)是为Python语言定义的Web服务器和Web应用程序或框架之间的一种简单而通用的接口。自从WSGI被开发出来以后,许多其它语言中也出现了类似接口。

可以将WSGI看做是一种协议,据说之所以Python中有很多web框架,就是因为WSGI调用非常方便。uWSGI是WSGI这一协议的实现。在实际使用过程中,uWSGI代替了python manage.py runserver的作用,当然还有其他作用。

最早的Web服务器只支持静态html。随着网站也越来越复杂,出现了动态技术。但是服务器并不能直接运行 php,asp这样的文件,因此需要一个第三方,与第三方做个约定,我把请求参数发送给你,然后我接收你的处理结果给客户端。这个约定就是 common gateway interface,简称cgi。这个协议可以用vb,c,php,python 来实现。

简单地说,cgi是Web App与Http Server之间的桥梁。

除了cgi,还有wsgi(Web Service Gateway Interface)。WSGI所在层的位置低于CGI,与CGI不同的是WSGI具有很强的伸缩性且能运行于多线程或多进程的环境下,这是因为WSGI只是一份标准并没有定义如何去实现。实际上WSGI并非CGI,因为其位于web应用程序与web服务器之间,而web服务器可以是CGI。

所有均开始于settings文件


如果我们已经创建了一个hello应用(如何创建,请参考本文开始时提到的两个教程),并且使用下面的语句运行:

python manage.py runserver 0.0.0.0:8000
那么,当我们访问 http://192.168.1.100:8000/hello/ 时(前面是一个局域网内的ip,8000是端口号),发生了什么?
 
所有均开始于settings文件。当你运行python manage.py runserver,脚本将在于manage.py同一个目录下查找名为setting.py的文件。这个文件包含了所有有关这个Django项目的配置信息(都是大写的变量名称,例如 TEMPLATE_DIRS、DATABASE_NAME等)。最重要的设置是ROOT_URLCONF,它将作为URLconf告诉Django在这个站点中哪些Python的模块将被用到。
 
打开文件settings.py你将看到如下内容:
ROOT_URLCONF = 'mysite.urls'
相对应的文件是mysite/urls.py
 
当访问URL /hello/ 时,Django根据ROOT_URLCONF的设置装载URLconf 。然后按顺序逐个匹配URLconf里的URLpatterns,直到找到一个匹配的。当找到这个匹配的URLpatterns就调用相关联的view函数,并把HttpRequest对象作为第一个参数(一个视图功能必须返回一个HttpResponse)。一旦做完,Django将完成剩余的工作:转换Python的对象到一个合适的带有HTTP头和body的Web Response(例如,网页内容)。
 
从http requese到http response是通过下面的过程实现的:

访问请求 -> setting.py -> urls.py -> views.py -> hello()
 
# urls.py

from django.conf.urls import url, include
from django.contrib import admin
from mysite.views import hello admin.autodiscover() urlpatterns = [
url(r'^hello/$', hello),
]
# viwes.py

from django.http import HttpResponse

def hello(request):
return HttpResponse("Hello World!")

uWSGI与Django之间的通讯


uWSGI与Django之间的通讯是通过wsgi.py文件实现的,这个文件在创建Django project后就生成了。这里的设置中最主要的一点就是正确的指出settings.py文件的位置。因为Django中的一切都始于这个文件。这些都使用Django的默认配置就可以了。

# wsgi.py
"""
WSGI config for mysite project. It exposes the WSGI callable as a module-level variable named ``application``. For more information on this file, see
https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/
""" import os from django.core.wsgi import get_wsgi_application # 这里已经指定了settings文件的位置
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings") application = get_wsgi_application()

一些命令:

# 安装uwsgi

$ pip install uwsgi

# 如果 python manage.py runserver 0.0.0.0:8000 可以运行成功,则可以使用下面的命令代替django本身的runserver功能(为了可以使用8000端口,需要先修改防火墙设置)

$ uwsgi --http :8000 --module mysite.wsgi  # 在项目的根目录运行该命令(与运行python manage.py的目录相同),参考"图1"中的目录结构

但是在与nginx联合使用时,端口号由nginx中的配置决定,在uwsgi中就不用配置端口号了(由于nginx与uwsgi之间通过socket通信,所以直接访问该端口号就可以访问整个django程序)。

下面是一个配置文件的例子,配置完成后可以在6001端口访问django程序,nginx与uwsgi之间通过"/run/uwsgi/metDNA.sock"进行通信。

server {
listen 6001;
server_name localhost; # 这里可以根据实际情况填写域名或localhost
charset utf-8;
client_max_body_size 50M; location / {
include uwsgi_params;
# include conf.d/corsheaders.conf;
uwsgi_pass unix:///run/uwsgi/metDNA.sock;
} # Django media
location /media { # 设置www.ourlab.cn/media的具体路径,这里是django项目配置文件中的`MEDIA_ROOT`的位置
# your Django project's media files - amend as required
alias /mnt/data/metdna-upload;
} location /static { # django项目的静态文件夹位置,即`STATIC_ROOT`的位置
# your Django project's static files - amend as required
# first project's static files path
alias /mnt/data/www/metDNA/metDNA/static/static_root;
}
}

更多详情,可以参考:https://uwsgi-docs.readthedocs.io/en/latest/tutorials/Django_and_nginx.html

uwsig的配置:

  • 具体配置,可以参考这里
  • 因为在配置文件中设置了touch-reload参数,所以更新django代码后,可以使用 touch /path/to/wsgi.py 加载更新,而不用重启整个django项目;
  • 使用uwsgi的emperor模式:/usr/bin/uwsgi --emperor /etc/uwsgi/sites,sites文件夹中放的是uwsgi的配置文件mysite.ini(可以放多个django项目相关的配置文件)。该模式始终处于运行状态,如果要停止该django项目,可以重命名sites文件夹下对应的配置文件;

Instances under the control of the emperor should never dies.
If you want to fully stop an instance, simply remove/rename/move the instance config file in a way that the emperor rule will never match.

nginx的配置


由于一开始不熟悉,因此nginx的配置花了很长时间。其中的关键点是:不同的server之间是无法共用端口号(port)的,因此如果要使用同一个端口号,例如80端口,那么所有的路由都要配置在一个server中。

  • 配置文件位置:/etc/nginx/ ;
  • 可以将自定义的配置文件放在目录 /etc/nginx/conf.d/,由于在主配置文件 /etc/nginx/nginx.conf 中包含有 include /etc/nginx/conf.d/*.conf; 这条语句,所以该目录下所有的 .conf 文件都会被加载;
  • 自定义的配置文件,可以参考这里nginx.conf,主要是指定端口号和server name(网站域名);

值得注意的是,上面配置文件中的sock文件,例如unix:/run/uwsgi/lipidCCS.sock,nginx的用户和uwsgi的用户需要同时对其进行读写操作,因此都需要相应的权限。靠近前端用户的nginx和靠近后端django程序的uwsgi就是通过这个sock文件进行通信的。

一些命令:

# 重启服务:

$ sudo systemctl restart nginx.service

其他


进程管理:进程管理的工具也有很多,uWSGI中的Emperor mode与进程管理工具具有相似的功能,两者似乎无法共用。我选择的是Supervisor。

Supervisor (http://supervisord.org) 是一个用 Python 写的进程管理工具,可以很方便的用来启动、重启、关闭进程(不仅仅是 Python 进程)。除了对单个进程的控制,还可以同时启动、关闭多个进程,比如很不幸的服务器出问题导致所有应用程序都被杀死,此时可以用 supervisor 同时启动所有应用程序而不是一个一个地敲命令启动。

uwsgi程序中的Emperor mode,会与Supervisor相互影响;Emperor mode的作用与Supervisor差不多,但自己感觉Supervisor更好用一些

 
php文件:php的运行需要安装php-fpm

重大修订:

第一次修订于2017年12月20日,补充了uwsgi相关配置的说明,对配置文件添加了注释;

第二次修订于2018年12月27日,勘误以及修复链接(这是每年这个时间都要写网站的节奏啊!);

参考:

https://zh.wikipedia.org/wiki/%E7%B6%B2%E9%A0%81%E4%BC%BA%E6%9C%8D%E5%99%A8

https://zh.wikipedia.org/wiki/Berkeley%E5%A5%97%E6%8E%A5%E5%AD%97

https://zh.wikipedia.org/wiki/Web%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%BD%91%E5%85%B3%E6%8E%A5%E5%8F%A3

http://djangobook.py3k.cn/2.0/

http://uwsgi-docs.readthedocs.io/en/latest/tutorials/Django_and_nginx.html

https://www.quora.com/What-are-the-differences-between-nginx-and-gunicorn # 这里讲了为什么要使用nginx和gunicorn(作用同uWSGI)

http://data-eater.com/python-worker/

http://www.shellwjl.com/2016/03/07/ali_flask_wsgi_Nginx/

利用Django构建web应用及其部署的更多相关文章

  1. 全面解读Python Web开发框架Django,利用Django构建web应用及其部署

    全面解读Python Web开发框架Django Django是一个开源的Web应用框架,由Python写成.采用MVC的软件设计模式,主要目标是使得开发复杂的.数据库驱动的网站变得简单.Django ...

  2. [Python] 利用Django进行Web开发系列(一)

    1 写在前面 在没有接触互联网这个行业的时候,我就一直很好奇网站是怎么构建的.现在虽然从事互联网相关的工作,但是也一直没有接触过Web开发之类的东西,但是兴趣终归还是要有的,而且是需要自己动手去实践的 ...

  3. [Python] 利用Django进行Web开发系列(二)

    1 编写第一个静态页面——Hello world页面 在上一篇博客<[Python] 利用Django进行Web开发系列(一)>中,我们创建了自己的目录mysite. Step1:创建视图 ...

  4. 利用Django进行Web开发

    Web就是用来表示Internet主机上供外界访问的资源的.网页也统称为web资源.Internet上供外界访问的Web资源主要分为如下两类: 静态web资源:指web页面中供人们浏览的数据始终是不变 ...

  5. Eclipse+Maven构建web项目及部署时Maven lib依赖问题的解决

    目录 Eclipse中m2e插件构建web项目的步骤 Maven工具构建web项目再导入Eclipse的步骤 [一].Eclipse中m2e插件构建web项目的步骤 第一步:创建项目,按照 New – ...

  6. python的Django构建web应用

    创建一个网上购物的网站 首先创建一个简单的python项目,然后在终端输入pip install django 安装Django框架 然后输入django-admin startproject pys ...

  7. maven学习(下)利用Profile构建不同环境的部署包

    接上回继续,项目开发好以后,通常要在多个环境部署,象我们公司多达5种环境:本机环境(local).(开发小组内自测的)开发环境(dev).(提供给测试团队的)测试环境(test).预发布环境(pre) ...

  8. 如何利用docker 构建golang线上部署环境

    公司最近开发了一个项目是用golang 写的,现在要部署到线上环境去,又不想在服务器上装单独的golang,决定用docker 封装下,直接打到镜像里面,然后就直接在hub.docker.com上面搜 ...

  9. maven学习利用Profile构建不同环境的部署包

    项目开发好以后,通常要在多个环境部署,象我们公司多达5种环境:本机环境(local).(开发小组内自测的)开发环境(dev).(提供给测试团队的)测试环境(test).预发布环境(pre).正式生产环 ...

随机推荐

  1. JAVA作业之动手动脑

    1.枚举类型是引用类型,但例子输出结果引用的不是同一个类型.枚举类型可以有自己的属性(参数)和方法,枚举类型可以以独立的文件存在. 2.第一个"X+Y="+X+Y的运行结果是默认为 ...

  2. VC中C++数值范围的确定

    1. Visual C++ 32 位和 64 位编译器可识别本文后面的表中的类型. 如果其名称以两个下划线 (__) 开始,则数据类型是非标准的. 下表中指定的范围均包含起始值和结束值. 类型名称 字 ...

  3. hihocoder 二分

    题目 一个简单的二分,只是想说明一下,如若要查找一个数组中某个数的下标可以直接用lower_bound()这个函数.只是要考虑到要查找的数不在数组中的这种情况. #include <cstdio ...

  4. python之函数2

    Python 函数 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提高应用的模块性,和代码的重复利用率.你已经知道Python提供了许多内建函数,比如print().但你也 ...

  5. 分频器的verilog设计

    笔者最近由于实验室老师的任务安排重新又看了一下分频器的verilog实现,现总结如下,待以后查看之用(重点是查看计数器计到哪个值clk_out进行状态翻转) 1.偶数分频占空比为50% 其实质还是一个 ...

  6. Android-okhttp下载网络图片并设置壁纸

    在AndroidManifest.xml配置网络访问权限: <!-- 访问网络是危险的行为 所以需要权限 --> <uses-permission android:name=&quo ...

  7. 【转】 js数组 Array 交集 并集 差集 去重

    原文:http://blog.csdn.net/ma_jiang/article/details/52672762 最劲项目需要用到js数组去重和交集的一些运算,我的数组元素个数可能到达1000以上, ...

  8. 【转】JS浮点数运算Bug的解决办法

    37.5*5.5=206.08 (JS算出来是这样的一个结果,我四舍五入取两位小数) 我先怀疑是四舍五入的问题,就直接用JS算了一个结果为:206.08499999999998 怎么会这样,两个只有一 ...

  9. gunicorn运行显示connection in use解决办法

    运行gunicorn后显示如下错误: root@iZ2ze2gihbn4ot85zlcdxdZ:~/myproject# gunicorn -w 4 -b 0.0.0.0:5000 myapp:app ...

  10. nginx官方文档 之 http负载均衡 学习笔记

    一.负载均衡 算法 大致可以分两类: (1)不能保证用户的每一次请求都通过负载均衡到达同一服务器. (2)可保证用户的每一次请求都通过负载均衡到达同一服务器. 第二类的应用场景: 1.如果服务器有缓存 ...