django框架
web框架的本质
理解1:连接前端与数据库的中间介质
理解2:socket服务端
纯手撸web框架
1.搭建socket服务端
import socket server = socket.socket() server.bind(('127.0.0.1', 8082)) server.listen(5) while True: sock, addr = server.accept() data = sock.recv(1024) # 此处一会儿需要按照步骤2、3做修改 sock.send(b'hello jasonNB')
浏览器访问响应无效>>>:HTTP协议
2.浏览器发送请求
# 服务端响应的数据需要符合HTTP响应格式 sock.send(b'HTTP1.1 200 OK\r\n\r\nhello jasonNB')
3.根据网址后缀的不同获取不同的页面内容
# 将客户端请求相关数据先转成字符串 data_str = data.decode('utf8') # 研究发现可以采用字符串切割获取路由 current_path = data_str.split(' ')[1] # 根据后缀的不同返回不同的内容 if current_path == '/login': sock.send(b'hello jason login!!!') elif current_path == '/register': sock.send(b'hello jason register') else: sock.send(b'404 jason error')
总结
1.socket代码过于重复 2.针对请求数据处理繁琐 3.后缀匹配逻辑过于LowB
wsgiref模块介绍
是一种内置模块,很多web框架底层使用的模块
功能1:封装了socket代码
功能2:处理了请求数据
from wsgiref import simple_server def run(request, response): """ :param request: 请求相关的数据 :param response: 响应相关的数据 :return: 返回给客户端的展示数据 """ response('200 OK', []) # 固定编写 无需掌握 return [b'hello jason'] if __name__ == '__main__': server = simple_server.make_server('127.0.0.1', 8080, run) '''监听本机8080端口 一旦有请求访问 自动触发run方法的执行''' server.serve_forever() # 模块封装了socket代码并将请求数据处理成诸多k:v键值对
2.路由对应响应
# run函数体中添加下列代码 current_path = request.get("PATH_INFO") if current_path == '/login': return [b'hello login html'] elif current_path == '/register': return [b'hello register html'] return [b'404 error']
3.路由拆分流程
1.当有很多路由和响应的情况下不可能无限制编写if判断语句,应该设置对应关系并动态调用
def register(request): return 'register' def login(request): return 'login' def error(request): with open(r'templates/error.html', 'r', encoding='utf8') as f: return f.read() urls = ( ('/login',login), ('/register',register) ) def run(request, response): func_name = None for url_tuple in urls: if current_path == url_tuple[0]: # 先获取对应的函数名 func_name = url_tuple[1] # 一旦匹配上了 后续的对应关系就无需在循环比对了 break # for循环运行完毕之后 func_name也有可能是None if func_name: res = func_name(request) else: res = error(request) # 顺手将request也传给函数 便于后续数据的获取 return [res.encode('utf8')]
2.根据功能的不同拆分成不同的py文件
views.py
--存储核心业务逻辑(功能函数)
# 功能函数 def register(request): return 'register' def login(request): return 'login' def index(request): return 'index' def error(request): with open(r'templates/error.html', 'r', encoding='utf8') as f: return f.read()
urls.py
--存储网址后缀与函数名对应关系
from views import * # 后缀匹配 urls = ( ('/register', register), ('/login', login), ('/index', index), )
server.py
--存储启动及分配代码
from wsgiref import simple_server from urls import urls from views import error def run(request, response): response('200 OK', []) current_path = request.get("PATH_INFO") func_name = None for url_tuple in urls: # ('/register', register) if current_path == url_tuple[0]: func_name = url_tuple[1] break if func_name: res = func_name(request) else: res = error(request) return [res.encode('utf8')] if __name__ == '__main__': server = simple_server.make_server('127.0.0.1', 8080, run) server.serve_forever()
总结:拆分后好处在于要想新增一个功能,只需要在views.py中编写函数,urls.py添加对应关系即可
动态网页
页面数据来源于后端
静态网页
页面数据直接写死
示例:
1.访问某个网址后缀,后端代码获取当前时间,并将该时间传到html文件上再返回给浏览器展示给用户看
读取html内容(字符串类型),然后利用字符串替换,最后再返回给浏览器
def get_time(request): # 1.获取当前时间 import time c_time = time.strftime('%Y-%m-%d %X') # 2.读取html文件 with open(r'templates/get_time.html','r',encoding='utf8') as f: data = f.read() # 3.思考:如何给字符串添加一些额外的字符串数据>>>:字符串替换 new_data = data.replace('random_str',c_time) return new_data
<h1>展示后端获取的时间数据</h1> <span>random_str</span>
2.将字典传递给页面内容,并且在页面上还可以通过类似于后端的操作方式操作该数据
模板语法>>>:jinja2模块
jinja2模板语法
from views import * urls = [ ('/get_dict', get_dict_func), ]
views.py
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
get_dict_page.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> </head> <body> <h1>获取字典数据</h1> <p>{{ d1 }}</p> <p>{{ d1.name }}</p> <p>{{ d1['age'] }}</p> <p>{{ d1.get('person_list') }}</p> </body> </html>
create table userinfo(id int primary key auto_increment, name varchar(32),age int); insert into userinfo(name,age) values('alex',18),('bob',25),('cindy',19);
后端
urls.py
from views import * urls = [ ('/get_user', get_user_func) ]
views.py
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
前端
get_user_page.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>
1.django
大而全,自身自带的功能组件非常的多,类似于航空母舰
2.flask
小而精,自身自带的功能组件非常的少,类似于游骑兵
几乎所有的功能都需要依赖于第三方模块
3.tornado
异步非阻塞,速度极快效率极高甚至可以充当游戏服务端
ps:sanic、fastapi...
1.版本问题
- django1.X:同步 1.11
- django2.X:同步 2.2
- django3.X:支持异步 3.2
- django4.X:支持异步 4.2
ps:版本之间的差异其实不大 主要是添加了额外的功能
2.运行django注意事项
- django项目中所有的文件名目录名不要出现中文
- 计算机名称尽量也不要出现中文
- 一个pycharm尽量就是一个完整的项目(不要嵌套 不要叠加)
- 不同版本的python解释器与不同版本的django可能会出现小问题
启动如果报错,根据提示找到修改widgets.py文件第152行源码,删除最后的逗号即可
1.下载
pip3 install django 默认最新版
pip3 install django==版本号 指定版本
pip3 install django==2.2.22
pip下载模块会自动解决依赖问题(会把关联需要用到的模块一起下了)
2.验证是否下载成功
cmd窗口直接输入django-admin,有一长串结果展示表明成功
常见命令
1. cmd创建django项目
先切换到D盘根目录 D:
django-admin startproject 项目名
C:\Users\独孤傲>D: D:\>django-admin startproject mysite
2.cmd启动django项目
终端启动一定要先切回到django的目录下:cd 项目名
python38 manage.py runserver ip:port
'''IP:PORT可以不写,默认在本地8000端口起服务'''
浏览器输入端口号会出现以下界面,说明启动成功
3. cmd修改端口号
按Ctrl+C键退回到原目录,重新输入启动命令,并加上要修改的端口号
PyCharm操作django
PyCharm直接创建和启动django项目
pycharm会自动创建templates文件夹
创建步骤:
注意:有些版本的PyCharm直接创建的django项目在启动时会出现如下报错:
只要修改一下settings文件就好了:
注意:
点击右上角启动,注意红色框框里的内容不要选错。不要右键运行。
如果django项目启动不起来,或者一直报错,有可能是终端里面启动了一个,Pycharm里面启动了一个,要先停掉一个,或者修改端口号
Pycharm修改端口号
1. 右上角选择Edit Configurations
2. 在Port处输入新的端口号,应用即可
补充
不小心删除了django项目,按照下面步骤操作即可:
django类似于是一所大学,app类似于大学里面的各个学院。
django里面的app类似于某个具体的功能模块
user app 所有用户相关的都写在user app下
goods app 所有商品相关的都写在goods app下
命令行创建应用
python38 manage.py startapp 应用名 # 应用名尽量跟业务相关,不要用编号
pycharm创建应用
1. pycharm模拟终端创建
2. 新建django项目可以默认创建一个应用,并且自动注册
这种创建方法有一个好处,会在配制文件里自动注册
其他方式创建的app一定要去settings.py中注册(切记)
INSTALLED_APPS = [ 'myapp.apps.MyappConfig', # 完整写法 'myapp' # 简写 ]
补充:pycharm智能创建应用(前期不熟练的情况下建议不要使用)
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会)
终端手动创建templates目录
mkdir templates
再次强调:配置文件中还需要配置路径
[os.path.join(BASE_DIR,'templates'),]
重要名词讲解
urls.py 路由层
views.py 视图层
models.py 模型层
templates 模板层
from django.shortcuts import HttpResponse
HttpResponse # 返回字符串类型的数据
djangoProject/urls.py
访问结果:
2. 返回html页面
from django.shortcuts import render
render # 返回html页面
views.py
from django.shortcuts import render
def login_func(request): user_dict = {'name':'alex', 'pwd': 123, 'person_list':['aaa','bbb','ccc']} return render(request,'login.html',{'d1':user_dict})
get_dict.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> </head> <body> <h1>你好啊 django框架</h1> <p>{{ d1 }}</p> <p>{{ d1.name }}</p> <p>{{ d1.pwd }}</p> <p>{{ d1.person_list }}</p> </body> </html>
urls.py
访问结果:
3. 重定向
from django.shortcuts import redirect redirect # 重新定位到指定的网页
views.py
from django.shortcuts import redirect def fun_func(request): return redirect('https://www.douban.com/')
urls.py
访问结果: