Django开篇 - Web应用

一 Web应用的组成


接下来我们学习的目的是为了开发一个Web应用程序,而Web应用程序是基于B/S架构的,其中B指的是浏览器,负责向S端发送请求信息,而S端会根据接收到的请求信息返回相应的数据给浏览器,需要强调的一点是:S端由server和application两大部分构成,如图所示:
上图:Web应用组成

二 开发一个Web应用

我们无需开发浏览器(本质即套接字客户端),只需要开发S端即可,S端的本质就是用套接字实现的,如下

# S端
import socket

def make_server(ip, port, app):  # 代表server
    sock = socket.socket()
    sock.bind((ip, port))
    sock.listen(5)
    print('Starting development server at http://%s:%s/' %(ip,port))
    while True:
        conn, addr = sock.accept()

        # 1、接收浏览器发来的请求信息
        recv_data = conn.recv(1024)
        # print(recv_data.decode('utf-8'))

        # 2、将请求信息直接转交给application
        res = app(recv_data)

        # 3、向浏览器返回消息(此处并没有按照http协议返回)
        conn.send(res)

        conn.close()

def app(environ):  # 代表application
    # 处理业务逻辑
    return b'hello world'

if __name__ == '__main__':
    make_server('127.0.0.1', 8008, app)  # 在客户端浏览器输入:http://127.0.0.1:8008 会报错(注意:请使用谷歌浏览器)

目前S端已经可以正常接收浏览器发来的请求消息了,但是浏览器在接收到S端回复的响应消息b‘hello world‘时却无法正常解析 ,因为浏览器与S端之间收发消息默认使用的应用层协议是HTTP,浏览器默认会按照HTTP协议规定的格式发消息,而S端也必须按照HTTP协议的格式回消息才行,所以接下来我们详细介绍HTTP协议
HTTP协议详解链接地址:https://www.cnblogs.com/Du704/p/11713916.html

S端修订版本:处理HTTP协议的请求消息,并按照HTTP协议的格式回复消息

# S端
import socket

def make_server(ip, port, app): # 代表server
    sock = socket.socket()
    sock.bind((ip, port))
    sock.listen(5)
    print('Starting development server at http://%s:%s/' %(ip,port))
    while True:
        conn, addr = sock.accept()

        # 1、接收并处理浏览器发来的请求信息
        # 1.1 接收浏览器发来的http协议的消息
        recv_data = conn.recv(1024)

        # 1.2 对http协议的消息加以处理,简单示范如下
        ll=recv_data.decode('utf-8').split('\r\n')
        head_ll=ll[0].split(' ')
        environ={}
        environ['PATH_INFO']=head_ll[1]
        environ['method']=head_ll[0]

        # 2:将请求信息处理后的结果environ交给application,这样application便无需再关注请求信息的处理,可以更加专注于业务逻辑的处理
        res = app(environ)

        # 3:按照http协议向浏览器返回消息
        # 3.1 返回响应首行
        conn.send(b'HTTP/1.1 200 OK\r\n')
        # 3.2 返回响应头(可以省略)
        conn.send(b'Content-Type: text/html\r\n\r\n')
        # 3.3 返回响应体
        conn.send(res)

        conn.close()

def app(environ): # 代表application
    # 处理业务逻辑
    return b'hello world'

if __name__ == '__main__':
    make_server('127.0.0.1', 8008, app)

此时,重启S端后,再在客户端浏览器输入:http://127.0.0.1:8008 便可以看到正常结果hello world了。

我们不仅可以回复hello world这样的普通字符,还可以夹杂html标签,浏览器在接收到消息后会对解析出的html标签加以渲染

# S端
import socket

def make_server(ip, port, app):
    sock = socket.socket()
    sock.bind((ip, port))
    sock.listen(5)
    print('Starting development server at http://%s:%s/' %(ip,port))
    while True:
        conn, addr = sock.accept()

        recv_data = conn.recv(1024)
        ll=recv_data.decode('utf-8').split('\r\n')
        head_ll=ll[0].split(' ')
        environ={}
        environ['PATH_INFO']=head_ll[1]
        environ['method']=head_ll[0]

        res = app(environ)

        conn.send(b'HTTP/1.1 200 OK\r\n')
        conn.send(b'Content-Type: text/html\r\n\r\n')
        conn.send(res)

        conn.close()

def app(environ):
    # 返回html标签
    return b'<h1>hello web</h1><img src="https://www.baidu.com/img/bd_logo1.png"></img>'

if __name__ == '__main__':
    make_server('127.0.0.1', 8008, app)

更进一步我们还可以返回一个文件,例如timer.html,内容如下

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h2>{{ time }}</h2>
</body>
</html>

S端程序如下

# S端
import socket

def make_server(ip, port, app): # 代表server
    sock = socket.socket()
    sock.bind((ip, port))
    sock.listen(5)
    print('Starting development server at http://%s:%s/' %(ip,port))
    while True:
        conn, addr = sock.accept()

        recv_data = conn.recv(1024)
        ll=recv_data.decode('utf-8').split('\r\n')
        head_ll=ll[0].split(' ')
        environ={}
        environ['PATH_INFO']=head_ll[1]
        environ['method']=head_ll[0]

        res = app(environ)

        conn.send(b'HTTP/1.1 200 OK\r\n')
        conn.send(b'Content-Type: text/html\r\n\r\n')
        conn.send(res)

        conn.close()

def app(environ):
    # 处理业务逻辑:打开文件,读取文件内容并返回
    with open('timer.html', 'r', encoding='utf-8') as f:
        data = f.read()
    return data.encode('utf-8')

if __name__ == '__main__':
    make_server('127.0.0.1', 8008, app)

上述S端为浏览器返回的都是静态页面(内容都固定的),我们还可以返回动态页面(内容是变化的)

# S端
import socket

def make_server(ip, port, app): # 代表server
    sock = socket.socket()
    sock.bind((ip, port))
    sock.listen(5)
    print('Starting development server at http://%s:%s/' %(ip,port))
    while True:
        conn, addr = sock.accept()

        recv_data = conn.recv(1024)
        ll=recv_data.decode('utf-8').split('\r\n')
        head_ll=ll[0].split(' ')
        environ={}
        environ['PATH_INFO']=head_ll[1]
        environ['method']=head_ll[0]

        res = app(environ)

        conn.send(b'HTTP/1.1 200 OK\r\n')
        conn.send(b'Content-Type: text/html\r\n\r\n')
        conn.send(res)

        conn.close()

def app(environ):
    # 处理业务逻辑
    with open('timer.html', 'r', encoding='utf-8') as f:
        data = f.read()

    import time
    now = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
    data = data.replace('{{ time }}', now)  # 字符串替换
    return data.encode('utf-8')

if __name__ == '__main__':
    make_server('127.0.0.1', 8008, app) # 在浏览器输入http://127.0.0.1:8008,每次刷新都会看到不同的时间

三 Web框架的由来

综上案例我们可以发现一个规律,在开发S端时,server的功能是复杂且固定的(处理socket消息的收发和http协议的处理),而app中的业务逻辑却各不相同(不同的软件就应该有不同的业务逻辑),重复开发复杂且固定的server是毫无意义的,有一个wsgiref模块帮我们写好了server的功能,这样我们便只需要专注于app功能的编写即可

# wsgiref实现了server,即make_server
from wsgiref.simple_server import make_server 

def app(environ, start_response): # 代表application
    # 1、返回http协议的响应首行和响应头信息
    start_response('200 OK', [('Content-Type', 'text/html')])

    # 2、处理业务逻辑:根据请求url的不同返回不同的页面内容
    if environ.get('PATH_INFO') == '/index':
        with open('index.html','r', encoding='utf-8') as f:
            data=f.read()
    elif environ.get('PATH_INFO') == '/timer':
        with open('timer.html', 'r', encoding='utf-8') as f:
            data = f.read()
        import time
        now = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        data = data.replace('{{ time }}', now)  # 字符串替换
    else:
        data='<h1>Hello, web!</h1>'

    # 3、返回http响应体信息,必须是bytes类型,必须放在列表中
    return [data.encode('utf-8')]

if __name__ == '__main__':
    # 当接收到请求时,wsgiref模块会对该请求加以处理,然后后调用app函数,自动传入两个参数:
    # 1 environ是一个字典,存放了http的请求信息
    # 2 start_response是一个功能,用于返回http协议的响应首行和响应头信息
    s = make_server('', 8011, app) # 代表server
    print('监听8011')
    s.serve_forever() # 在浏览器输入http://127.0.0.1:8011/index和http://127.0.0.1:8011/timer会看到不同的页面内容

timer.html已经存在了,新增的index.html页面内容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>主页</h1>
</body>
</html>

上述案例中app在处理业务逻辑时需要根据不同的url地址返回不同的页面内容,当url地址越来越多,需要写一堆if判断,代码不够清晰,耦合程度高,所以我们做出以下优化

# 处理业务逻辑的函数
def index(environ):
    with open('index.html', 'r', encoding='utf-8') as f:
        data = f.read()
    return data.encode('utf-8')

def timer(environ):
    import datetime
    now = datetime.datetime.now().strftime('%y-%m-%d %X')
    with open('timer.html', 'r', encoding='utf-8') as f:
        data = f.read()
    data = data.replace('{{ time }}', now)
    return data.encode('utf-8')

# 路径跟函数的映射关系
url_patterns = [
    ('/index', index),
    ('/timer', timer),
]

from wsgiref.simple_server import make_server

def app(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])

    # 拿到请求的url并根据映射关系url_patters执行相应的函数
    reuqest_url = environ.get('PATH_INFO')
    for url in url_patterns:
        if url[0] == reuqest_url:
            data = url[1](environ)
            break
    else:
        data = b'404'

    return [data]

if __name__ == '__main__':
    s = make_server('', 8011, app)
    print('监听8011')
    s.serve_forever()

随着业务逻辑复杂度的增加,处理业务逻辑的函数以及url_patterns中的映射关系都会不断地增多,此时仍然把所有代码都放到一个文件中,程序的可读性和可扩展性都会变得非常差,所以我们应该将现有的代码拆分到不同文件中
插图:

mysite # 文件夹
    ├── app01 # 文件夹
    │   └── views.py
    ├── mysite # 文件夹
    │   └── urls.py
    └── templates # 文件夹
    │   ├── index.html
    │   └── timer.html
    ├── main.py

views.py 内容如下:

# 处理业务逻辑的函数
def index(environ):
    with open('templates/index.html', 'r',encoding='utf-8') as f: # 注意文件路径
        data = f.read()
    return data.encode('utf-8')

def timer(environ):
    import datetime
    now = datetime.datetime.now().strftime('%y-%m-%d %X')
    with open('templates/timer.html', 'r',encoding='utf-8') as f: # 注意文件路径
        data = f.read()
    data=data.replace('{{ time }}',now)
    return data.encode('utf-8')

urls.py内容如下:

# 路径跟函数的映射关系
from app01.views import * # 需要导入views中的函数

url_patterns = [
    ('/index', index),
    ('/timer', timer),
]

main.py 内容如下:

from wsgiref.simple_server import make_server
from mysite.urls import url_patterns  # 需要导入urls中的url_patterns

def app(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])

    # 拿到请求的url并根据映射关系url_patters执行相应的函数
    reuqest_url = environ.get('PATH_INFO')
    for url in url_patterns:
        if url[0] == reuqest_url:
            data = url[1](environ)
            break
    else:
        data = b'404'

    return [data]

if __name__ == '__main__':
    s = make_server('', 8011, app)
    print('监听8011')
    s.serve_forever()

至此,我们就针对application的开发自定义了一个框架,所以说框架的本质就是一系列功能的集合体、不同的功能放到不同的文件中。有了该框架,可以让我们专注于业务逻辑的编写,极大的提高了开发web应用的效率(开发web应用的框架可以简称为web框架),比如我们新增一个业务逻辑,要求为:浏览器输入http://127.0.0.1:8011/home 就能访问到home.html页面,在框架的基础上具体开发步骤如下:
步骤一:在templates文件夹下新增home.html
步骤二:在urls.py的url_patterns中新增一条映射关系

url_patterns = [
    ('/index', index),
    ('/timer', timer),
    ('/home', home), # 新增的映射关系
]

步骤三:在views.py中新增一个名为home的函数

def home(environ):
    with open('templates/home.html', 'r',encoding='utf-8') as f:
        data = f.read()
    return data.encode('utf-8')

我们自定义的框架功能有限,在Python中我们可以使用别人开发的、功能更强大的Django框架

四 Django框架的安装与使用

在使用Django框架开发web应用程序时,开发阶段同样依赖wsgiref模块来实现Server的功能,我们使用Django框架是为了快速地开发application

4.1 安装

目前在企业开发中Django框架使用的主流版本为1.11.x版本,最新版本为2.x,我们主要讲解1.11版本,同时会涉及2.x的新特性

pip3 install django==1.11.18 # 在命令行执行该命令

4.2 使用

4.2.1 快速创建并启动Django项目


如果使用的是我们自定义的框架来开发web应用,需要事先生成框架包含的一系列基础文件,然后在此基础上进行开发。
如果使用的是Django框架来开发web应用,同样需要事先生成Django框架包含的一系列基础文件,然后在此基础上进行开发。
但Django框架更为方便的地方在于它已经为我们提供了一系列命令来帮我们快速地生成这一系列基础文件

# 在命令行执行以下指令,会在当前目录生成一个名为mysite的文件夹,该文件夹中包含Django框架的一系列基础文件
django-admin startproject mysite

创建功能模块

cd mysite # 切换到mysite目录下,执行以下命令
python manage.py startapp app01 # 创建功能模块app01,此处的startapp代表创建application下的一个功能模块。例如我们要开发application是京东商城,京东商城这个大项目下有一个订单管理模块,我们可以将其命名为app01

运行

python manage.py runserver 8001 # 在浏览器输入:http://127.0.0.1:8001 会看到Django的欢迎页面。

4.2.2 Django项目目录结构


截目录树的图(按照下述目录截图)

mysite # 文件夹
    ├── app01 # 文件夹
    │   └── migrations # 文件夹
    │   └── admin.py
    │   └── apps.py
    │   └── models.py
    │   └── tests.py
    │   └── views.py
    ├── mysite # 文件夹
    │   └── settings.py
    │   └── urls.py
    │   └── wsgi.py
    └── templates # 文件夹
    ├── manage.py

关键文件介绍

-manage.py---项目入口,执行一些命令
-项目名
    -settings.py  全局配置信息
    -urls.py      总路由,请求地址跟视图函数的映射关系
-app名字
    -migrations   数据库迁移的记录
    -models.py    数据库表模型
    -views.py     处理业务逻辑的函数,简称视图函数

4.2.3 基于Pycharm创建Django项目

4.2.4 基于Django实现的一个简单示例

(1)url.py
from django.contrib import admin
from django.conf.urls import url
#导入views模块
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),

    # r'^index/$' 会正则匹配url地址的路径部分
    url(r'^index/$',views.index), # 新增地址http://127.0.0.1:8001/index/与index函数的映射关系
]
(2)视图
from django.shortcuts import render

# 必须定义一个request形参,request相当于我们自定义框架时的environ参数
def index(request):
    import datetime
    now=datetime.datetime.now()
    ctime=now.strftime("%Y-%m-%d %X")

    return render(request,"index.html",{"ctime":ctime}) # render会读取templates目录下的index.html文件的内容并且用字典中的ctime的值替换模版中的{{ ctime }}
(3)模版

在templates目录下新建文件index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h4>当前时间:{{ ctime }}</h4>

</body>
</html>

测试:

python manage.py runserver 8001 # 在浏览器输入:http://127.0.0.1:8001/index/ 会看到当前时间。

4.2.5 Django框架的分层与请求生命周期

综上,我们使用Django框架就是为了开发application,而application的工作过程本质就是根据不同的请求返回不同的数据,Django框架将这个工作过程细分为如下四层去实现
1、路由层(根据不同的地址执行不同的视图函数,详见urls.py)
2、视图层(定义处理业务逻辑的视图函数,详见views.py)
3、模型层 (跟数据库打交道的,详解models.py)
4、模板层(待返回给浏览器的html文件,详见templates)
django请求生命周期

这体现了一种解耦合的思想,下面我们开始详细介绍每一层

原文地址:https://www.cnblogs.com/Du704/p/11713951.html

时间: 2024-10-11 00:56:07

Django开篇 - Web应用的相关文章

利用Django构建web应用及其部署

注:很久之前就有了学习Django的想法,最近终于有机会做了一次尝试.由于Django的详细教程很多,我在这里就不再详述了,只是将整个开发流程以及自己在学习Django中的一些思考记录在此. System:CentOS Linux release 7.2.1511 (Core) Django: 1.10 Python: 2.7.5 推荐两个非常好的教程: The Django Book(中文版):我自己一开始是参考这个教程学习的,非常有意思的是这个教程中有大量的评论,几乎每段都有,从10年开始一

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

1 写在前面 在没有接触互联网这个行业的时候,我就一直很好奇网站是怎么构建的.现在虽然从事互联网相关的工作,但是也一直没有接触过Web开发之类的东西,但是兴趣终归还是要有的,而且是需要自己动手去实践的.Web开发的途径有好多种,比如传统的.Net,还有很火爆的Java.Python作为一种灵活好学的脚本语言,已经越来越受程序员的欢迎和热捧,甚至成为程序员的必备技能.Django是Python的Web开放框架,好多人说学习Python就是在学Django,从这也可以看出Django的强大.博主也是

[zz]阿里云计算:CentOS+nginx+Django+Postgresql web环境搭建

原文链接: http://www.cnblogs.com/AllStarGIS/p/3788518.html 参考链接: 1. http://www.cnblogs.com/zhouej/archive/2012/03/25/2379646.html 2. http://ec58.com/archives/2836 最近在在万网和阿里云上分别购买了一个域名和一台云服务器,打算用来做点什么.昨天吃完晚饭稍作休息开始对这个新奇的玩意作了些了解并着手配置其运行环境,今早凌晨4点多才弄得7788,为此也

使用 Python 和 Django 搭建 Web 应用

使用 Python 和 Django 搭建 Web 应用 简介 Django 是 Python 开发的 Web 框架.使用 Django 搭建 Web 应用很方便. 写本文时 django 的最新版本为 1.4,但本文不关注新版本的特性,只搭建一个简单的应用. 安装 Django 本文以 CentOS 6.2 为例进行安装: 安装 python # yum install python 本文使用的是 CentOS 6.2 Desktop,默认安装了 python. 查看一下 python 的版本

Nginx+uWSGI+Django部署web服务器

目录 Nginx+uWSGI+Django部署web服务器 环境说明 前言 搭建项目 Django部署 编辑luffy/luffy/settings.py 编辑luffy/app01/views.py 编辑luffy/luffy/urls.py 运行并测试 uWSGI部署 测试运行uWSGI 使用uWSGI运行django项目 uWSGi热加载Djangoa项目 部署nginx nginx配置uwsgi和django django部署static文件 重新加载nginx进行测试 测试nginx

Django之Web框架原理

Django之Web框架原理 为什么要学习所谓的Web框架原理 因为不管是django也好 市场上最火的什么MVC框架也好他就是基于这一套东西,来给你进行一些功能的封装让你用着特别方便,我们要做的不止是学会这些框架学框架的时候要有自己的想法,要知道这个框架的这个地方自己好像试着做也能做出来废话不多说 铁子 奥力给!! Web框架是什么 Web 应用框架,或者简单的说是“Web 框架”,其实是建立 web 应用的一种方式.从简单的博客系统到复杂的富 AJAX 应用,web 上每个页面都是通过写代码

Python &amp; PyCharm &amp; Django 搭建web开发环境(续)

由于Django自带轻量级的server,因此在前篇博文中,默认使用该server,但实际生产中是不允许这么干的,生产环境中通常使用Apache Httpd Server结合mod_wsgi.so来做后端服务器. 以下部署环境为:Python2.7.6 1.安装httpd-2.2.25-win32-x86-no_ssl.msi 2.将下载好的mod_wsgi.so 放在 D:\Program Files\Apache Software Foundation\Apache2.2\modules 模

[Python] 利用Django进行Web开发

第一步:下载并安装django 首先,在Django官网上下载适合自己Python的Django版本,在安装Django前首先确定你已成功安装了python.         Windows系统下安装Django: 解压缩下载的Django压缩包,找到里面的setup.py文件,然后打开cmd命令窗口,在其对应的路径下执行如下命令: python setup.py install Linux系统下安装Django: 以此在shell中输入如下命令: $ tar xzvf Django-*.tar

Python自动化运维之26、Django系列-Web框架本质

一.Web框架本质 众所周知,对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端. #!/usr/bin/env python #coding:utf-8 import socket def handle_request(client): buf = client.recv(1024) client.send("HTTP/1.1 200 OK\r\n\r\n") client.send("Hello, Seven"