手写简易web框架

import socket

server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5)

spe_conn, address = server.accept()  # 阻塞态

data = spe_conn.recv(1024)
data_str = data.decode('utf8')

current_path = data_str.split('\r\n')[0].split(' ')[1]

spe_conn.send(b'HTTP/1.1 200 ok\r\n\r\n')

if current_path == '/index':
    with open(r'手写web前端页面.html', 'rb') as fr:
        spe_conn.send(fr.read())

elif current_path == '/login':
    spe_conn.send(b'login')

else:
    spe_conn.send(b'404 error')

spe_conn.close()

基于wsgiref模块写web框架

ValueError

  1. [{'xxx': 'jason'}], not enough values to unpack(expect 2, got 1)
  2. ['xxx', 'jason'], too many values to unpack (expect 2)
  3. [('xxx', 'jason'), ]

views.py

存放函数, 这些函数被称为视图函数, 视图层

urls.py

存放路由后缀与视图函数的对应关系, 路由层

templates文件夹

存放html模板文件

动静态网页

  • 静态页面, 数据在html页面上是写死的, 不会发生任何改变
  • 数据是实时获取的, eg: 1. 后端代码动态获取当前时间; 2. 数据是从数据库中查询出来的
  • 后端数据-->html页面-->前端-->浏览器渲染

jinja2模板语法

  • 专门用来出来后端数据与html页面的交互
  • 模板语法: 能够在html页面上, 用类似于python的语法操作后端传递过来的数据
def get_user_dic(env):
    from jinja2 import Template
    user_dic = {'user_name': 'jason', 'hobby': ['read', 'book', 'run']}
    with open(r'templates/get_user_dic.html', 'r', encoding='utf8') as fr:
        data = fr.read()  # 在内存中读取HTML模板

    temp = Template(data)  # 得到temp对象
    res = temp.render(userDic=user_dic)  # 根据HTML模板中的模板语法, 将user_dic渲染到HTML模板中, 在内存中生成一个完整的HTML文件(即res)
    # print(res)
    return res

'''
res对应整个html页面在内存中渲染后的结果

模板语法部分对应结果:
<p>{'user_name': 'jason', 'hobby': ['read', 'book', 'run']}</p>
<p>jason</p>
<p>['read', 'book', 'run']</p>
<p>read</p>
<p>book</p>
<p>run</p>
'''
<!--模板语法-->
<p>{{userDic}}</p>
<p>{{userDic.user_name}}</p>
<p>{{userDic['hobby']}}</p>
<p>{{userDic.get('hobby').0}}</p>
<p>{{userDic.get('hobby').1}}</p>
<p>{{userDic.get('hobby').2}}</p>

基于jinjia2数据库中的数据

  • pymysql.connect-->Connect-->__init__

  • 模板的渲染: 将后端处理好的数据, 在内存中读取HTML模板, 并通过jinjia2模板语法生成一个完整的HTML文件的过程

  • 模板的渲染是在后端完成的, 与前端无关

  • pymsql复习

    import pymysql
    
    client = pymysql.connect(
        host='127.0.0.1',
        port=3306,
        user='root',
        password='Cql123456',
        db='django',
        charset='utf8',
        autocommit=True
    )
    cursor = client.cursor(pymysql.cursors.DictCursor)  # 将查询出的数据组织成一个字典
    sql = "select id, username, password from user_info"  # 当数据量特别大时, *会降低查询效率
    affect_rows = cursor.execute(sql)  # sql注入: 利用mysql注释语法钻漏洞, 关键数据交给execute拼接
    user_lt = cursor.fetchall()
    

python三大主流web框架

web框架请求流程图

python三大主流web框架

django:

  • 优点: 大而全, 自带的组件和功能非常多, 类似于航空母舰
  • 缺点: 写小项目是可能会大材小用
  • socket部分用的wsgiref, 路由匹配和模板语法自己写的

flask:

  • 优点: 小而精, 更多依赖于第三方组件, 类似于游骑兵
  • 缺点: 受限于第三方模块的影响比较大
  • 如果将flask所有第三方模块加起来, 能够直接盖过django
  • socket部分用的werkzeug, 路由匹配自己写的, 模板语法用的jinjia2

tornado:

  • 异步非阻塞, 通过回调函数处理异步任务结果, tornado甚至可以用来开发游戏服务器
  • socket, 路由匹配和模板语法都是自己写的

django安装

安装django注意事项

  1. 计算机名称不能有中文
  2. python解释器不要使用3.7, 推荐版本3.4~3.6
  3. 一个pycharm窗口, 只跑一个django项目
  4. django版本以1.11.11为主
  5. 验证django是否安装成功: 在cmd中执行django-admin, 看是否有反应

命令行创建django项目

  1. 创建django项目: django-admin startproject 项目名

  2. 启动django项目: manage.py runserver127.0.0.1:8080

  3. app: django是一个以开放app为主要功能的web框架

    一个django项目类似于一所大学, 而app类似于大学里的学院

    可以根据功能的不同开放多个app, 一个app对应一个具体的功能模块

    创建app: python manage.py startapp app名

  4. 不会自动创建templates文件夹, 创建后手动将templates文件夹路径添加到settings.py中

    settings-->TEMPLATES-->'DIRS': [os.path.join(BASE_DIR, 'templates')]

pycharm创建django项目

1.创建的app需要在django配置文件中注册才能生效: 'INSTALLED_APPS = [..., app02.apps.App02Config'] 通过反射找到所创建的app

2.一定要确保同一个端口同一时间只能启一个django项目

3.更改使用的数据库, settings-->DATABASES

django文件功能

django项目名

  • 项目同名的文件夹
    • settings.py: 配置文件
    • urls.py: 路由与视图函数对应关系
  • manage.py: django的入口文件
  • 应用名文件夹
    • migrations文件夹: 所有数据库相关的操作记录
    • admin.py: django中admin后台管理
    • apps.py: 注册app使用
    • models.py: 存放数据库相关的模型表类
    • test.py: 测试文件
    • views.py: 处理业务逻辑的视图函数

django小白必会三板斧

  • HttpResponse: 返回字符串

    def index(request):  # 参数request <==> env, 必须传
        return HttpResponse('一脸懵逼')
    
  • render: 返回HTML文件, 可以给HTML文件传值

    def login(request):
        user_dic = {'username': 'jason', 'password': '123'}
        return render(request, 'login.html', {'userDic': user_dic})
    
  • redirect: 重定向, 1. 直接写本网站的路径后缀; 2. 写其他网站全路径

    def home(request):
        return redirect('/login')
    	# return redirect('https://www.baidu.com')
    
  • 重启机制: 内有检测机制, 实时检测所有文件的变化, 有时会产生代码还没写完就自动重启报错的情况, 不用管