Django框架相关
推导模拟实现Django框架
代码编写web框架
web框架的本质
从上图来看,web框架就是连接前端与数据库的中间介质,负责对数据进行处理,以主要的业务逻辑为支持
编写思路
如果是从代码角度来看,web框架就是我们之前所写的socket服务端,对客户端传来的数据与请求进行处理,将数据库的数据反馈到客户端
那么我们使用代码编写web框架的思路大概如下
1.编写socket服务端代码
2.浏览器访问响应无效>>>:HTTP协议
sock.send(b'HTTP/1.1 200 OK\r\n\r\n')
# 添加相应的数据打包格式
3.根据网址后缀的不同获取不同的页面内容
/index、/login、
4.想办法获取到用户输入的后缀>>>:请求数据
5.找到网址后缀所在位置
GET /login HTTP/1.1
请求文件的首行位置
请求的两种类型
GET请求
索要数据
POST请求
提交数据
6.对请求数据进行处理获取网址后缀
利用字符串的切割属性,用空格对数据进行切割,索引1
data.split(' ')[1]
整体代码
import socket
server = socket.socket() # TCP UDP
server.bind(('127.0.0.1', 8080)) # IP PORT
server.listen(5) # 半连接池
while True:
sock, address = server.accept() # 等待连接
data = sock.recv(1024) # 字节(bytes)
# print(data.decode('utf8')) # 解码打印
sock.send(b'HTTP/1.1 200 OK\r\n\r\n')
data_str = data.decode('utf8') # 先转换成字符串
target_url = data_str.split(' ')[1] # 按照空格切割字符串并取索引1对应的数据
# print(target_url) # /index /login /reg
if target_url == '/index':
# sock.send(b'index page')
with open(r'myhtml01.html','rb') as f:
sock.send(f.read())
elif target_url == '/login':
sock.send(b'login page')
else:
sock.send(b'home page!')
代码初步优化
实际的代码写出来之后,只是初步具备了一些功能,但是还是存在一些问题
1.socket代码过于重复
2.针对请求数据处理繁琐
3.后缀匹配逻辑过于低端(if...elif...分支重复)
优化思路:
借助于wsgiref模块对代码进行优化
作为python的内置模块,它有很强大的功能,是大多数web框架底层使用的代码,对于socket代码进行了封装,对数据的处理方法也进行了封装,极大地简化了我们的代码编写
from wsgiref.simple_server import make_server
def run(request, response):
"""
:param request: 请求相关数据
:param response: 响应相关数据
:return: 返回给客户端的真实数据
"""
response('200 OK', []) # 固定格式 不用管它
# print(request) 是一个处理之后的大字典
path_info = request.get('PATH_INFO')
if path_info == '/index':
return [b'index']
elif path_info == '/login':
return [b'login']
return [b'hello wsgiref module']
if __name__ == '__main__':
server = make_server('127.0.0.1', 8080, run) # 实时监听127.0.0.1:8080 一旦有请求过来自动给第三个参数加括号并传参数调用
server.serve_forever() # 启动服务端
1.固定代码启动服务端
2.查看处理之后的request,数据是以字典的形式组成的
3.根据不同的网址后缀返回不同的内容>>>:研究大字典键值对
PATH_INFO对应的就是网址的后缀,直接用.get方法取出
根据不同结果进行判定,决定返回数据内容
4.立刻解决上述纯手写的问题一与问题二
函数封装优化
那么,最后的问题,关于条件的筛选,我们可以参考以往的内容
将代码进行函数封装,将他们以网页的后缀作为键,函数名作为值封装为功能字典,当后缀名符合时直接在字典中取值进行函数调用即可
views.py 存储核心业务逻辑(功能函数)
urls.py 存储网址后缀与函数名对应关系
templates目录 存储html页面文件
如果仅仅是这样还是不够的,request中包含了所有用户请求信息,那么如果在之后的业务拓展中我们需要使用达到数据,那么我们就需要在传递数据时将这个字典传递出去
那么我们在拆分封装函数时,就可以将这个字典当做参数传递给函数,这样在之后拓展时我们就可以调用字典中的数据
到这里我们的框架基本已经趋于完善
但是网页中的内容也决定了网页分为动态网页与静态网页两种
动静态网页
动态网页
页面数据来源于后端,实时从后端获取数据并进行展示
静态网页
页面数据直接写在前端,不会与后端产生互动
我们可以在后端定义一个函数,当用户访问某个指定的网页时,后端代码获取当前时间,并将时间传递到网页进行展示
这样的话,我们需要将获取到的时间传递到HTML文档中指定的标签中,首先要先读取到HTML内的内容,将指定标签的内容更换为我们所获取到的时间然后返回到浏览器页面
字符串类型的数据我们可以使用replace进行替换,那么如果是其他类型的数据呢,这个时候就需要使用到另一个内置模块:jinja2
jinja2模块
它同样也是python的内置模块,直接使用pip工具进行下载或者在pycharm中进行下载即可
pip3 install jinja2
from jinja2 import Template
def get_dict_func(request):
user_dict = {'name': 'jason', 'age': 18, 'person_list': ['阿珍', '阿强', '阿香', '阿红']}
with open(r'templates/get_dict_page.html', 'r', encoding='utf8') as f:
data = f.read()
temp_obj = Template(data) # 将页面数据交给模板处理
res = temp_obj.render({'d1': user_dict}) # 给页面传了一个 变量名是d1值是字典数据的数据
return res
<p>{{ d1 }}</p>
<p>{{ d1.name }}</p>
<p>{{ d1['age'] }}</p>
<p>{{ d1.get('person_list') }}</p>
jinja2模块最大的作用就是可以让我们在HTML文档中以类似于在python中操作数据一样去操作我们传递到HTML中的数据
{% for user_dict in user_data_list %}
<tr>
<td>{{ user_dict.id }}</td>
<td>{{ user_dict.name }}</td>
<td>{{ user_dict.age }}</td>
</tr>
{% endfor %}
它还支持进行for循环,但是我们需要搞清楚的是,所有数据的处理都是在jinja2模块处理好之后才传递到HTML文件中的,并不是真的在HTML文档中操作数据
那么对于前端、后端以及数据库三者的联动,真正实现web框架我们也就可以实现了
服务端主体代码
from wsgiref.simple_server import make_server
from views import *
from urls import urls
def run(request, response):
"""
:param request: 请求相关数据
:param response: 响应相关数据
:return: 返回给客户端的真实数据
"""
response('200 OK', []) # 固定格式 不用管它
path_info = request.get('PATH_INFO') # /index
func_name = None # 定义一个用于后续存储函数名的变量
for url_tuple in urls: # (后缀,函数名)
if path_info == url_tuple[0]:
func_name = url_tuple[1]
break # 一旦匹配成功 后续无序匹配直接结束
if func_name:
res = func_name(request)
else:
res = error_func(request)
return [res.encode('utf8')]
if __name__ == '__main__':
server = make_server('127.0.0.1', 8080, run) # 实时监听127.0.0.1:8080 一旦有请求过来自动给第三个参数加括号并传参数调用
server.serve_forever() # 启动服务端
urls.py
from views import *
urls = [
('/index', index_func),
('/login', login_func),
('/reg', reg_func),
('/logout', logout_func),
('/get_time', get_time_func),
('/get_dict', get_dict_func),
('/get_user', get_user_func)
]
views.py
def index_func(request):
return 'index function'
def login_func(request):
with open(r'templates/myhtml02.html', 'r', encoding='utf8') as f:
return f.read()
# return 'login function'
def reg_func(request):
return 'reg function'
def error_func(request):
return '404 Not Found'
def logout_func(request):
return 'logout function'
def get_time_func(request):
import time
ctime = time.strftime('%Y-%m-%d %X')
with open(r'templates/get_time_page.html', 'r', encoding='utf8') as f:
data = f.read()
# 在后端先把数据传递到文件内容上 之后再发送给浏览器 字符串的替换
res = data.replace('sadkasjdklad', ctime)
return res
from jinja2 import Template
def get_dict_func(request):
user_dict = {'name': 'jason', 'age': 18, 'person_list': ['阿珍', '阿强', '阿香', '阿红']}
with open(r'templates/get_dict_page.html', 'r', encoding='utf8') as f:
data = f.read()
temp_obj = Template(data) # 将页面数据交给模板处理
res = temp_obj.render({'d1': user_dict}) # 给页面传了一个 变量名是d1值是字典数据的数据
return res
import pymysql
def get_user_func(request):
# 连接数据库操作数据
conn = pymysql.connect(
user='root',
password='123',
host='127.0.0.1',
port=3306,
database='day51',
charset='utf8',
autocommit=True
)
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
sql1 = "select * from userinfo;"
cursor.execute(sql1)
user_data = cursor.fetchall() # [{},{},{},{}]
# 读取页面数据
with open(r'templates/get_user_page.html', 'r', encoding='utf8') as f:
data = f.read()
temp_obj = Template(data)
res = temp_obj.render({'user_data_list': user_data})
return res
templates目录内文件
user.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<div class="row">
<h1 class="text-center">数据展示</h1>
<a href="/index">点我试试</a>
<div class="col-md-8 col-md-offset-2">
<table class="table table-hover table-striped">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Age</th>
</tr>
</thead>
<tbody>
<!-- [{},{},{},{} ]-->
{% for user_dict in user_data_list %}
<tr>
<td>{{ user_dict.id }}</td>
<td>{{ user_dict.name }}</td>
<td>{{ user_dict.age }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>
这样我们也就实现了整个web框架的手写工作
Python中主流web框架
所谓网络框架是指这样的一组Python包,它能够使开发者专注于网站应用业务逻辑的开发,而无须处理网络应用底层的协议、线程、进程等方面。这样能大大提高开发者的工作效率,同时提高网络应用程序的质量
对于最初接触框架的程序员,建议不要混着学习,否则对于框架的把我不够熟练容易彻底搞混而导致任何框架都不能熟练掌握
大而全,自身自带的功能组件非常的多,类似于航空母舰
异步非阻塞,速度极快效率极高
小而精 自身自带的功能组件非常的少 类似于游骑兵
几乎所有的功能都需要依赖于第三方模块
还有sanic、fastapi等比较小众的框架
Django简介
到目前为止,Django的最新版本发展到了4.0,其中1.X与2.X属于同步架构,3.X与4.X都已经支持异步架构,而在上图中,LTS版本是历代Django框架中最为稳定的版本
对于版本而言,个版本之间的底层差异并不大,可能只是在旧版的基础上添加了新的功能,而在学习过程中,建议使用2.2版本
运行Django的注意事项
1.django项目中所有的文件名目录名不要出现中文
2.计算机名称尽量也不要出现中文
3.一个pycharm窗口尽量是一个完整的项目(不要嵌套,不要叠加)
4.不同版本的python解释器与不同版本的django可能会出现小问题(例如配置文件中的路径拼接问题)
解决方法:
os.path.join(BASE_DIR,'templates')
上图中的问题只需根据提示查找widgets.py源码第152行,删除掉最后的逗号
Django基本使用
下载
pip3 install django 默认最新版
pip3 install django==版本号 指定版本
pip3 install django==2.2.22
pip下载模块会自动解决依赖问题(会把关联需要用到的模块一起下了)
验证是否下载成功可以在cmd中输入以下指令
django-admin
常用命令
1.创建django项目
django-admin startproject 项目名
2.启动django项目
cd 项目名
python38 manage.py runserver ip:port
pycharm自动创建Django项目
会自动创建templates文件夹 但是配置文件中可能会报错
os.path.join(BASE_DIR,'templates')
Django app的概念
这里的APP并不是我们日常使用的软件,我们可以用类比方法来进行理解
django类似于是一所大学 app类似于大学里面的各个学院
django里面的app类似于某个具体的功能模块
user app 所有用户相关的都写在user app下
goods app 所有商品相关的都写在goods app下
命令行创建应用
python38 manage.py startapp 应用名
pycharm创建应用
新建django项目可以默认创建一个 并且自动注册
app注册机制
创建的app一定要去settings.py中注册
INSTALLED_APPS = [
'app01.apps.App01Config', # 完整写法
'app02'] # 简写
django主要目录结构
django项目目录名
django项目同名目录
settings.py 配置文件
urls.py 存储网址后缀与函数名对应关系(不严谨)
wsgi.py wsgiref网关文件
db.sqlite3文件 django自带的小型数据库(项目启动之后才会出现)
manage.py 入口文件(命令提供)
应用目录
migrations目录 存储数据库相关记录
admin.py django内置的admin后台管理功能
apps.py 注册app相关
models.py 与数据库打交道的(非常重要)
tests.py 测试文件
views.py 存储功能函数(不严谨)
templates目录
存储html文件(命令行不会自动创建 pycharm会)
配置文件中还需要配置路径
[os.path.join(BASE_DIR,'templates'),]
名词讲解
网址后缀 路由
函数 视图函数
类 视图类
重要名词讲解
urls.py 路由层
views.py 视图层
models.py 模型层
templates 模板层
Django必懂三功能
from django.shortcuts import render,HttpResponse,redirect
HttpResponse 返回字符串类型的数据
render 返回html页面并且支持传值
redirect 重定向
标签:框架,py,request,Django,user,func,django,data
From: https://www.cnblogs.com/lf17603472426/p/16967199.html