分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 代码编程

web框架之Django

发布时间:2023-09-06 01:27责任编辑:蔡小小关键词:暂无标签

web开发介绍

互联网刚兴起的那段时间大家都热衷于CS架构,也就是Client/Server模式。每个用户的电脑上安装一个Client,就像QQ这种终端软件。
随着互联网的发展,开发客户端显得越来越‘重’,BS架构(Browser/Server模式)越来越流行,也就是用户只需要一个浏览器就足够了。

前端性能优化的方式
  1. 减少DOM操作
  2. 部署前,图片压缩,代码压缩
  3. 优化JS代码结构,减少冗余代码
  4. 减少HTTP请求,合理设置 HTTP缓存
  5. 使用内容分发CDN加速
  6. 静态资源缓存
  7. 图片延迟加载

一个页面从输入URL到页面加载显示完成,这个过程中都发生了什么?

输入地址之后:

  1. 浏览器查找域名的IP地址
  2. 这一步包括DNS具体的查找过程,包括:浏览器缓存->系统缓存->路由器缓存…
  3. 浏览器向Web服务器发送一个HTTP请求
  4. 服务器的永久重定向响应(从 http://example.com 到 http://www.example.com)
  5. 浏览器跟踪重定向地址
  6. 服务器处理请求
  7. 服务器返回一个HTTP响应
  8. 浏览器显示HTML
  9. 浏览器发送请求获取嵌入在HTML 中的资源(如图片、音频、视频、CSS、JS等等)
  10. 浏览器发送异步请求

Web框架

我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端。
这样我们就可以自己实现Web框架了。

 ?1 import socket ?2 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ?3 sock.bind((‘127.0.0.1‘, 8000)) ?4 sock.listen(5) ?5 while True: ?6 ????conn, addr = sock.accept() ?7 ????data = conn.recv(8096) ?8 ????conn.send(b"OK") ?9 ????conn.close()

可以说Web服务本质上都是在这十几行代码基础上扩展出来的。这段代码就是它们的祖宗。
用户的浏览器一输入网址,会给服务端发送数据,那浏览器会发送什么数据?怎么发?这个谁来定?
你这个网站是这个规定,他那个网站按照他那个规定,这互联网还能玩么?
所以,必须有一个统一的规则,让大家发送消息、接收消息的时候有个格式依据,不能随便写。

这个规则就是HTTP协议,以后你发送请求信息也好,回复响应信息也罢,都要按照这个规则来。

那HTTP协议是怎么规定消息格式的呢?

让我们首先看下我们在服务端接收到的消息是什么。

然后再看下我们浏览器收到的响应信息是什么。
响应头在浏览器的network窗口可以看到,我们看到的HTML页面内容就是响应体。本质上还是字符串,因为浏览器认识HTML,所以才会渲染出页面。

HTTP协议介绍

每个HTTP请求和响应都遵循相同的格式,一个HTTP包含Header和Body两部分,其中Body是可选的。
HTTP响应的Header中有一个Content-Type表明响应的内容格式。如text/html表示HTML网页。

 ?1 // 报头信息 ?2 HTTP/1.1 200 OK\r\n ?3 Header1:v1\r\n ?4 Header2:v2\r\n ?5 \r\n\r\n ----------> 与内容之间隔着两个换行符 ?6 // --------------------------------- 内容 ?7 Body...
让我们的Web框架在给客户端回复响应的时候按照HTTP协议的规则加上响应头,这样我们就实现了一个正经的Web框架了。
 ?1 import socket ?2 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ?3 sock.bind((‘127.0.0.1‘, 8000)) ?4 sock.listen(5) ?5 while True: ?6 ????conn, addr = sock.accept() ?7 ????data = conn.recv(8096) ?8 ????conn.send(b"HTTP/1.1 200 OK\r\n\r\n") ?9 ????conn.send(b"OK") 10 ????conn.close()

这样就结束了吗?
如何让我们的Web服务根据用户请求的URL不同而返回不同的内容呢?

小事一桩,我们可以从请求头里面拿到请求的URL,然后做一个判断。

 ?1 import socket ?2 sk = socket.socket() ?3 sk.bind(("127.0.0.1", 8080)) ?4 sk.listen(5) ?5 while True: ?6 ????conn, addr = sk.accept() ?7 ????data = conn.recv(8096) ?8 ????data_str = str(data, encoding="utf-8") ?# 把收到的字节数据转换成字符串类型 ?9 ????header = data_str.split("\r\n\r\n") ?# 将请求的数据按照\r\n\r\n分割 10 ????header_list = header[0].split("\r\n") ?# 按\r\n分割header 11 ????temp = header_list[0].split(" ") ?# 按空格分割第一行 12 ????url = temp[1] ?# 取到请求的URL 13 ????conn.send(b"HTTP/1.1 200 OK\r\n\r\n") ?# 发送响应头 14 ????if url == "/index/": 15 ????????conn.send(b"this is index page.") 16 ????else: 17 ????????conn.send(b"404 not found.") 18 ????conn.close()

解决了不同URL返回不同内容的需求。
但是问题又来了,如果有很多很多页面怎么办?难道要挨个判断?
当然不用,我们有更聪明的办法。

 ?1 import socket ?2 def index(): ?3 ????return b"this is index page." ?4 def login(): ?5 ????return b"this is login page." ?6 url_func_map = [ ?7 ????("/index/", index), ?8 ????("/login/", login) ?9 ] 10 sk = socket.socket() 11 sk.bind(("127.0.0.1", 8080)) 12 sk.listen(5) 13 while True: 14 ????conn, addr = sk.accept() 15 ????data = conn.recv(8096) 16 ????data_str = str(data, encoding="utf-8") ?# 把收到的字节数据转换成字符串类型 17 ????header = data_str.split("\r\n\r\n") ?# 将请求的数据按照\r\n\r\n分割 18 ????header_list = header[0].split("\r\n") ?# 按\r\n分割header 19 ????temp = header_list[0].split(" ") ?# 按空格分割第一行 20 ????url = temp[1] ?# 取到请求的URL 21 ????conn.send(b"HTTP/1.1 200 OK\r\ncontent-type:text/html; charset=utf-8\r\n\r\n") ?# 发送响应头 22 ????func_name = None ?# 将要执行的函数 23 ????for i in url_func_map: 24 ????????if i[0] == url: 25 ????????????func_name = i[1] 26 ????????????break ?# 跳出循环 27 ????if func_name: ?# 如果找到了要执行的函数 28 ????????response = func_name() 29 ????else: 30 ????????response = b"404 not found." 31 ????conn.send(response) 32 ????conn.close()

完美解决了不同URL返回不同内容的问题。
但是我不想仅仅返回几个字符串,我想给浏览器返回完整的HTML内容,这又该怎么办呢?

没问题,不管是什么内容,最后都是转换成字节数据发送出去的。
我可以打开HTML文件,读取出它内部的二进制数据,然后发送给浏览器。

 ?1 import socket ?2 def index(): ?3 ????with open("index.html", "rb") as f: ?4 ????????html_data = f.read() ?5 ????return html_data ?6 def login(): ?7 ????with open("login.html", "rb") as f: ?8 ????????html_data = f.read() ?9 ????return html_data 10 url_func_map = [ 11 ????("/index/", index), 12 ????("/login/", login) 13 ] 14 sk = socket.socket() 15 sk.bind(("127.0.0.1", 8080)) 16 sk.listen(5) 17 while True: 18 ????conn, addr = sk.accept() 19 ????data = conn.recv(8096) 20 ????data_str = str(data, encoding="utf-8") ?# 把收到的字节数据转换成字符串类型 21 ????header = data_str.split("\r\n\r\n") ?# 将请求的数据按照\r\n\r\n分割 22 ????header_list = header[0].split("\r\n") ?# 按\r\n分割header 23 ????temp = header_list[0].split(" ") ?# 按空格分割第一行 24 ????url = temp[1] ?# 取到请求的URL 25 ????conn.send(b"HTTP/1.1 200 OK\r\ncontent-type:text/html; charset=utf-8\r\n\r\n") ?# 发送响应头 26 ????func_name = None ?# 将要执行的函数 27 ????for i in url_func_map: 28 ????????if i[0] == url: 29 ????????????func_name = i[1] 30 ????????????break ?# 跳出循环 31 ????if func_name: ?# 如果找到了要执行的函数 32 ????????response = func_name() 33 ????else: 34 ????????response = b"404 not found." 35 ????conn.send(response) 36 ????conn.close()

这网页能够显示出来了,但是都是静态的啊。页面的内容都不会变化的,我想要的是动态网站。

没问题,我也有办法解决。我选择使用字符串替换来实现这个需求。

 ?1 import socket ?2 def index(): ?3 ????with open("index.html", "rb") as f: ?4 ????????html_data = f.read() ?5 ????return html_data ?6 def login(): ?7 ????with open("login.html", "rb") as f: ?8 ????????html_data = f.read() ?9 ????import time 10 ????time_str = str(time.time()) 11 ????html_str = str(html_data, encoding="utf-8") 12 ????new_html = html_str.replace("@@a@@", time_str) 13 ????return bytes(new_html, encoding="utf-8") 14 url_func_map = [ 15 ????("/index/", index), 16 ????("/login/", login) 17 ] 18 sk = socket.socket() 19 sk.bind(("127.0.0.1", 8080)) 20 sk.listen(5) 21 while True: 22 ????conn, addr = sk.accept() 23 ????data = conn.recv(8096) 24 ????data_str = str(data, encoding="utf-8") ?# 把收到的字节数据转换成字符串类型 25 ????header = data_str.split("\r\n\r\n") ?# 将请求的数据按照\r\n\r\n分割 26 ????header_list = header[0].split("\r\n") ?# 按\r\n分割header 27 ????temp = header_list[0].split(" ") ?# 按空格分割第一行 28 ????url = temp[1] ?# 取到请求的URL 29 ????conn.send(b"HTTP/1.1 200 OK\r\ncontent-type:text/html; charset=utf-8\r\n\r\n") ?# 发送响应头 30 ????func_name = None ?# 将要执行的函数 31 ????for i in url_func_map: 32 ????????if i[0] == url: 33 ????????????func_name = i[1] 34 ????????????break ?# 跳出循环 35 ????if func_name: ?# 如果找到了要执行的函数 36 ????????response = func_name() 37 ????else: 38 ????????response = b"404 not found." 39 ????conn.send(response) 40 ????conn.close()

这是一个简单的动态,我完全可以从数据库中查询数据,然后去替换我html中的对应内容,然后再发送给浏览器完成渲染。
这个过程就相当于HTML模板渲染数据。
本质上就是HTML内容中利用一些特殊的符号来替换要展示的数据。
我这里用的特殊符号是我定义的,其实模板渲染有个现成的工具:jinja2

 ?1 from jinja2 import Template ?2 template = Template(data) ?# 生成模板实例 ?3 template.render(data=data) ?# 渲染数据
pymysql连接数据库:
 ?1 conn = pymysql.connect(host="127.0.0.1", port=3306, user="root", passwd="xxx", db="xxx", charset="utf8") ?2 cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) ?3 cursor.execute("select name, age, department_id from userinfo") ?4 user_list = cursor.fetchall() ?5 cursor.close() ?6 conn.close()

创建一个测试的user表:

 ?1 CREATE TABLE user( ?2 ??id int auto_increment PRIMARY KEY, ?3 ??name CHAR(10) NOT NULL, ?4 ??habit CHAR(20) NOT NULL ?5 )engine=innodb DEFAULT charset=UTF8; ?6 

上述代码模拟了一个web服务的本质.
而对于真实开发中的Python Web程序来说,一般分为两部分:服务器程序和应用程序。
服务器程序负责对Socket服务器进行封装,并在请求到来时,对请求的各种数据进行整理。
应用程序则负责具体的逻辑处理。为了方便应用程序的开发,就出现了众多的Web框架,例如:Django、Flask、web.py等。
不同的框架有不同的开发方式,但是无论如何,开发出的应用程序都要和服务器程序配合,才能为用户提供服务。
这样,服务器程序就需要为不同的框架提供不同的支持。
这样混乱的局面无论对于服务器还是框架,都是不好的。
对服务器来说,需要支持各种不同框架,对框架来说,只有支持它的服务器才能被开发出的应用使用。
这时候,标准化就变得尤为重要。我们可以设立一个标准,只要服务器程序支持这个标准,框架也支持这个标准,那么它们就可以配合使用。
一旦标准确定,双方根据约定的标准各自进行开发即可。

WSGI(Web Server Gateway Interface)就是这样一种规范,它定义了使用Python编写的Web APP与Web Server之间接口格式,实现Web APP与Web Server间的解耦。

Python标准库提供的独立WSGI服务器称为wsgiref

 ?1 from wsgiref.simple_server import make_server ?2 def run_server(environ, start_response): ?3 ????start_response(‘200 OK‘, [(‘Content-Type‘, ‘text/html‘)]) ?4 ????return [bytes(‘<h1>Hello, web!</h1>‘, encoding=‘utf-8‘), ] ?5 if __name__ == ‘__main__‘: ?6 ????httpd = make_server(‘‘, 8000, run_server) ?7 ????print("Serving HTTP on port 8000...") ?8 ????httpd.serve_forever() ?9 
Django开发模式就是使用的wsgiref模块作为Web Server。

Django

安装与基本配置

 ?1 pip3 install django
 ?1 // 命令行创建项目 ?2 django-admin startproject mysite ?3 ??4 // 也可以用pycharm创建 ?5 
目录介绍:
 ?1 mysite/ ?2 ├── manage.py ?# 管理文件 ?3 └── mysite ?# 项目目录 ?4 ????├── __init__.py ?5 ????├── settings.py ?# 配置 ?6 ????├── urls.py ?# 路由 --> URL和函数的对应关系 ?7 ????└── wsgi.py ?# webserver ?--> wsgiref模块 ?8 
运行
 ?1 // 命令行启动方式 ?2 python manage.py runserver 127.0.0.1:8000

模板文件配置:

 ?1 # setting配置文件 ?2 TEMPLATES = [ ?3 ????{ ?4 ????????‘BACKEND‘: ‘django.template.backends.django.DjangoTemplates‘, ?5 ????????‘DIRS‘: [os.path.join(BASE_DIR, "template")], ?# template文件夹位置 ?6 ????????‘APP_DIRS‘: True, ?7 ????????‘OPTIONS‘: { ?8 ????????????‘context_processors‘: [ ?9 ????????????????‘django.template.context_processors.debug‘, 10 ????????????????‘django.template.context_processors.request‘, 11 ????????????????‘django.contrib.auth.context_processors.auth‘, 12 ????????????????‘django.contrib.messages.context_processors.messages‘, 13 ????????????], 14 ????????}, 15 ????}, 16 ] 17 ?18 # 也就是说以后存放的模板文件(html)存放位置, 可以改名字,但是相应的名字也要修改
静态文件配置:
 ?1 # 静态文件存放位置 ?2 STATIC_URL = ‘/static/‘ ?# HTML中使用的静态文件夹前缀 ?3 STATICFILES_DIRS = ( ?4 ????os.path.join(BASE_DIR, "static"), ?# 静态文件存放位置 ?5 ) ?6 # 也就是以后 css,js 存放文件的位置

新手必备三件套:

 ?1 ??2 from django.shortcuts import HttpResponse, render, redirect ?3 

web框架之Django

原文地址:http://www.cnblogs.com/wangyuanming/p/7900459.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved