• python之Djiango框架简介


    基础

    # HTTP响应状态码
        10X:服务端已经接受到你的数据了 你可以继续提交数据进行下一步操作
        20X:请求成功(200)
        30X:重定向(301,302)
        40X:请求错误(404)
        50X:服务端错误(500)
    
    # GET请求与POST请求
            GET请求:获取页面资源
            POST请求:朝服务端发送数据(让服务端校验该数据)

    一、Web框架本质

      所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端

    根据不同的路径返回不同的内容

      可以写几个简单页面,然后通过http://127.0.0.1:8080/页面名称  来访问对应的页面测试

    import socket
    
    server = socket.socket()  # 默认是TCP协议
    server.bind(('127.0.0.1',8080))  # 绑定IP端口
    server.listen(5)  # 监听 半链接池:保护计算机安全
    
    while True:
        conn, addr = server.accept()   # 等待连接
        data = conn.recv(1024)         # 接收客户端信息
        # 遵循HTTP协议,给回应的消息加上响应状态行
        conn.send(b'HTTP/1.1 200 OK
    
    ')
        res = data.decode('utf-8')
        current_path = res.split('
    ')[0].split(' ')[1]  # 字符串切割,获取路径
        # print(current_path)
        # 根据不同的路径返回不同的内容
        if current_path == '/index':
            # conn.send(b'index')
            with open('templates/111.html','rb') as f:
                conn.send(f.read())
        elif current_path == '/login':
            conn.send(b'login')
        else:
            conn.send(b'404')
        conn.close()

    浏览器访问页面请求信息:

      HTTP协议主要规定了客户端和服务器之间的通信格式

      响应相关信息可以在浏览器调试窗口的network标签页中看到。可以根据view信息切割获得需要请求的页面

    请求首行
    b'GET / HTTP/1.1
      
    请求头
    Host: 127.0.0.1:8080
    
    Connection: keep-alive
    
    Cache-Control: max-age=0
    
    Upgrade-Insecure-Requests: 1
    
    User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36
    
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
    
    Accept-Encoding: gzip, deflate, br
    
    Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
    
    Cookie: csrftoken=3vPenhmlRQb8Tvl4okwYM0OZpDCl3P7rbxvfpRDOHJy1zUApw89ugxM6OZSxhIBM
    
    
    
    请求体
    '
    http://127.0.0.1:8080/index
    view展开:

    根据不同的路径返回不同页面请求---函数版

    import socket
    
    sk = socket.socket()
    sk.bind(('127.0.0.1',8001))
    sk.listen()
    
    # 将不同的内容部分封装成函数
    def index(url):
        # 读取index.html页面内容
        with open("index.html",'rb',encoding="utf-8") as f:
            s = f.read()
        # 返回字节数据
        return bytes(s,encoding="utf-8")
    
    def login(url):
        with open("login.html",'rb',encoding="utf-8") as f:
            s = f.read()
        return bytes(s, encoding="utf-8")
    
    list1= [
        ("templates/111.html","/index"),
        ("templates/login.html",'/login'),
    ]
    
    while True:
        # 等待连接
        conn,add = sk.accept()
        data = conn.recv(1024) # 接收客户端发来的消息
        # 从data 中获取路径
        data = str(data,encoding='utf-8') # 把收到的字节类型数据转换成字符串
        print("data>>>",data)
        # 按
    切割,url是从浏览器发过来的消息中分离出来的访问路径
        url = data.split("
    ")[0].split(' ')[1]
        print("url>>>>",url)
        conn.send(b'HTTP/1.1 200 OK
    
    ') #遵循http协议,所以回复的消息也要加状态行
        # 根据不同的路径返回不同内容,reponse是具体的响应体
        func = None
        for i in list1:
            if i[0].split("/")[1] == url:
                func = i[1]
                break
        # print("func>>>",func)
        if func:
            reponse = func(url)
        else:
            reponse = b"404 not found!"
    
        conn.send(reponse)
        conn.close()
    
    # 还有点问题//TODO
    View Code

     二、服务器程序和应用程序 

      对于真实开发中的python web程序来说,一般会分为两部分:服务器程序和应用程序。
      服务器程序负责对socket服务器进行封装,并在请求到来时,对请求的各种数据进行整理。

      应用程序则负责具体的逻辑处理。为了方便应用程序的开发,就出现了众多的Web框架,例如:Django、Flask、web.py等。不同的框架有不同的开发方式,但是无论如何,开发出的应用程序都要和服务器程序配合,才能为用户提供服务。

      WSGI(Web Server Gateway Interface)就是一种规范,它定义了使用Python编写的web应用程序与web服务器程序之间的接口格式,实现web应用程序与web服务器程序间的解耦

      常用的WSGI服务器有uwsgi、Gunicorn。而Python标准库提供的独立WSGI服务器叫wsgiref,Django开发环境用的就是这个模块来做服务器。

    1.wsgiref 模块

      利用wsgiref模块来替换我们自己写的web框架的socket server部分

    # 未拆分前代码
    # http://127.0.0.1/index访问对应的名称到对应的页面
    from wsgiref.simple_server import make_server
    
    def index():
        return 'index'
    
    def reg():
        return 'res'
    
    def login():
        return 'login'
    
    def error():
        return '404'
    
    urls = [
        ('/index',index),
        ('/reg',reg),
        ('/login',login),
    ]
    
    def run(env,reponse):
        reponse('200 OK', [])  # 固定格式
        print(env)  # 将http格式的数据处理完毕,形成一个字段给你调用
        current_path = env.get('PATH_INFO')
        # if current_path == '/index':
        #     return [b'index']
        func = None
        for url_tuple in urls:
            if current_path == url_tuple[0]:
                func = url_tuple[1]   # 如果路由匹配上了,就回去对应的函数
                break
        if func:
            res = func()
        else:
            res = error()
        return [res.encode('utf-8')]
    
    if __name__ == '__main__':
        server = make_server('127.0.0.1',8080,run)  # 一直监听地址,只要有请求,就会给最后的函数或对象调用:run()执行
        server.serve_forever()
    
    # urls.py 存放访问链接后的页面
    
    from views import *
    urls = [
        ('/index',index),
        ('/reg',reg),
        ('/login',login),
    ]
    
    
    # views.py 存放访问页面函数
    def index():
        return 'index'
    
    def reg():
        return 'res'
    
    def login():
        return 'login'
    
    def error():
        return '404'
    
    # wsgiref.py存放启动
    from wsgiref.simple_server import make_server
    from urls import urls
    from views import *
    
    def run(env,response):
        response('200 OK', [])  # 固定格式 不需掌握
        print(env)  # 将http格式的数据处理完毕 形成一个字段给你调用
        current_path = env.get('PATH_INFO')
        func = None
        for url_tuple in urls:
            if current_path == url_tuple[0]:
                func = url_tuple[1]  # 如果路由匹配上了 就回去对应的函数
                break
        if func:
            res = func(env)
        else:
            res = error(env)
        return [res.encode('utf-8')]
    
    if __name__ == '__main__':
        server = make_server('127.0.0.1',8080,run)
        server.serve_forever()
    拆分后代码

    根据拆分后的代码,如果需要再添加访问页面,只需要在urls.py(路由与视图函数的映射关系)和views.py(视图函数)中增加对应的链接和函数就可以

    2.动静态页面

      静态网页:数据是写死的,一直不变

      动态网页:数据实时获取的,一直在改变(eg:数据库的数据或当前时间)

    2.1获取时间并显示在页面上:

    # 在上面拆分代码的基础上
    # urls.py增加
    urls = [
        ('/index',index),
        ('/reg',reg),
        ('/login',login),
        ('/get_time',get_time),
    ]
    
    # 对象视图views.py里增加函数
    import time
    def get_time():
        with open('templates/show_time.html','r',encoding='utf-8') as f:
            data = f.read()
        current_time = time.strftime('%Y-%m-%d %X')
        res = data.replace('timekkk',current_time)  # 字符串替换
        return res
    
    然后运行wsgiref.py就可以看到页面上显示动态的时间了,每次刷新时间都会变化

    2.2 给前端传字典并且字典可以取值

    # urls.py中新增对应访问路径
    from view2 import *
    
    urls2 = [
        ('/index', index),
        ('/reg', reg),
        ('/login', login),
        ('/get_time', get_time),
        ('/get_user', get_user),
    ]
    
    # views.py中新增对应函数
    from jinja2 import Template
    
    def get_user(env):
        user_dict = {'username': 'simon', 'password': '123'}
        with open('templates/get_user.html', 'r', encoding='utf-8') as f:
            data = f.read()
        tmp = Template(data)  # 实例化产生对象
        res = tmp.render(data=user_dict)  # 将user_dict传递给前端页面,前端页面用过变量名data就能够拿到user_dict字典
        return res
    
    # html页面body中设置
    {#传data这里就写data#}
    {{ data }}
    {#获取账号密码#}
    <p>{{data.username}}</p>
    <p>{{data['password']}}</p>
    <p>{{data.hobby.0}}</p>
    <p>{{data.hobby.1}}</p>

    模板渲染(雏形)

      后端产生的数据直接传递给前端页面,前端页面获取数据通过模板语法展示

    模板语法:

      {{}} 获取后端传递的数据,通过变量名(变量名相关的)

      {%%} 与逻辑相关的使用这个语法

      jinja2模板语法极为接近后端python语法

    {{ data }}
    <p>{{data.username}}</p>
    <p>{{data['password']}}</p>
    <p>{{data.hobby.0}}</p>
    <p>{{data.hobby.1}}</p>
     

    逻辑相关:

    {%for user_dict in user_list%}
    <tr>
    <td>{{user_dict.id}}</td>
    <td>{{user_dict.username}}</td>
    <td>{{user_dict.password}}</td>
    </tr>
    {%endfor%}

    2.3 数据库取值页面显示

    #urls2.py
    from view2 import *
    
    urls2 = [
        ('/get_data',get_data),
    ]
    
    # view2.py 新增函数
    from jinja2 import Template
    import pymysql
    
    def get_data(env):
        conn = pymysql.connect(
            host = '127.0.0.1',
            port = 3306,
            user = 'root',
            password = '123',
            database = 'test',
            charset = 'utf8',
            autocommit = True
        )
        cursor = conn.cursor(pymysql.cursors.DictCursor)
        cursor.execute('select * from userinfo')
        res = cursor.fetchall()
        with open('templates/get_data.html','r',encoding='utf-8') as f:
            data = f.read()
        tmp = Template(data)
        res1 = tmp.render(user_list = res)
        return res1
    
    # simple_server.py模块,和之前的没什么变化
    from wsgiref.simple_server import make_server
    from urls2 import urls2
    from view2 import *
    
    def run(env,reponse):
        reponse('200 OK', [])  # 固定格式
        print(env)  # 将http格式的数据处理完毕,形成一个字段给你调用
        current_path = env.get('PATH_INFO')
        # if current_path == '/index':
        #     return [b'index']
        func = None
        for url_tuple in urls2:
            if current_path == url_tuple[0]:
                func = url_tuple[1]   # 如果路由匹配上了,就回去对应的函数
                break
        if func:
            res = func(env)
        else:
            res = error(env)
        return [res.encode('utf-8')]
    
    if __name__ == '__main__':
        server = make_server('127.0.0.1',8080,run)  # 一直监听地址,只要有请求,就会给最后的函数或对象调用:run()执行
        server.serve_forever()
    
    # get_data.html前端页面代码
    # body内容
    <table>
        <thead>
            <tr>
                <th>id</th>
                <th>username</th>
                <th>password</th>
            </tr>
        </thead>
        <tbody>
            {%for user_dict in user_list%}
                <tr>
                    <td>{{user_dict.id}}</td>
                    <td>{{user_dict.username}}</td>
                    <td>{{user_dict.password}}</td>
                </tr>
            {%endfor%}
        </tbody>
    </table>
    数据库取值

    2.4 web服务渲染流程

      根据早上的流程,我们可以划出下面这个图

    2.5 web框架

    python主流三大框架:
    
       a.socket服务
    
       b:路由与视图函数映射关系
    
       c:模板渲染
      django:大而全 类似航空母舰
    
         a.用的别人的 wsgiref 上线之后会换成uwsgi;默认并发1000多,自己可以加nginx之类处理
    
         b.自己写的
    
         c.自己写的
      flask:小而精,轻量级框架
    
      a用的别人的  werkzeug  
      b自己写的
      c用的别人 jinja2
      tornado:异步非阻塞
    
        三者都是自己写的

    三、Django简介

    1.Django安装与注意事项

    # 主意事项
        1.计算机名称不能含有中文
        2.一个pycharm窗口就是一个工程(项目)
        3.项目文件夹不要有中文
    
    # ps:django版本: django 1.X(现在用的版本是这个1.11.11)
    
    # 安装
        pip3 install django
    # 或pycharm直接安装,可以指定版本specify version
    # 如果已经安装了高版本需要降低版本:pip3 uninstall django,然后重新指定安装:pip3 install django ===1.11.20 或pycharm指定版本安装 # 查看djiango是否安装成功 命令行界面:django-admin # 命令行创建django项目 django-admin startproject 项目名 ps:创建一个应用面的文件夹,里面有一个跟应用名同名的文件夹和一个manage.py的文件 # 命令行创建应用 django-admin startapp 应用名 # application 一个django项目 可以有多个应用,django是一款开发应用的web框架 django项目就类似是一所大学,而里面的应用就类似于一个个学院 # 命令行启动项目 python manage.py runserver 启动成功后浏览器可以访问:http://127.0.0.1:8000和http://127.0.0.1:8000/admin ps:命令行创建django项目不会自动新建templates文件夹,并且settings.py配置文件(TEMPLATES 列表中DIRS)不会自动写templates文件夹路径,所以都需要手动添加[os.path.join(BASE_DIR,'templates')]
    如下图:
    # pycharm创建 项目:File-->New Project-->Django-->Location(创建项目)-->More Settings创建应用--->Application name:应用名 在pycharm的命令行中创建应用:Tools-->Run manage.py TASK-->startapp 应用名 应用创建后需要再settings.py中注册应用INSTALLED_APPS里添加 启动后可以访问:http://127.0.0.1:8000 # 注意: 1 在django中创建的应用必须去settings文件中注册才能生效,否则django不识别 2 确保不要端口冲突

    2.Django项目目录结构

    项目名
        应用名文件夹
            migrations文件夹
                数据库迁移记录
            admin.py
                django admin后台管理相关
            models.py
                模型类
            views.py
                视图函数
            
        项目同名文件夹
            settings.py
                django暴露给用户可配置的配置文件
            urls.py
                路由与视图函数映射关系
        templates
            所有的html文件
        manage.py
            django入口文件

    3.Django 必会三板斧

    # django小白必会三板斧
    
    # HttpResponse:返回字符串
    # views.py
    def index(request):
        return HttpResponse("Hello Django index")
        
    # render:返回html页面
    def login(request):
        return render(request,'login.html')
        
    # redirect:重定向
    def home(request):
        return redirect('https://www.baidu.com')
    
    # urls.py配置文件中加对应访问路径
    from django.contrib import admin
    from django.urls import path
    from app01 import views
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('index/', views.index),
        path('login/', views.login),
        path('home/', views.home),
    ]

    4.静态文件配置

    # 动态实时监测到前缀的变化
    login.html
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="https://cdn.bootcss.com/jquery/3.4.0/jquery.min.js"></script>
        {% load static %}
        <link href="{% static 'bootstrap-3.3.7/css/bootstrap.min.css' %}" rel="stylesheet">
        <script src={% static "bootstrap-3.3.7/js/bootstrap.min.js" %}></script>
        
    </head>
    
    #用上述方法settings.py中接口前缀随便修改,也不需要修改html中的对应前缀
    
    # settings.py
    # 接口前缀:要想访问静态资源必须static打头:
    #     <script src="/static/bootstrap-3.3.7/js/bootstrap.min.js"></script>
    STATIC_URL = '/static/'
    # 新增文件放置路径
    STATICFILES_DIRS = [
        os.path.join(BASE_DIR,'static'),
        os.path.join(BASE_DIR,'static1'),
        os.path.join(BASE_DIR,'static2'),
    ]

    例:登录功能简单实现

    # form表单默认是get请求
        get请求携带的参数是拼接在url后面的以?开头&链接,默认method方式为Get
        ps:get请求可以携带参数 但是参数的大小有限制 最大4KB,并且是明文的
        http://127.0.0.1:8000/login/?username=simon&password=123
    
    # 如果改为method改为post提交,需要将settings.py中一行注释,否则会报403错误:
    # 'django.middleware.csrf.CsrfViewMiddleware', # 跨站请求伪造
    
    获取用户输入的框 都必须要有name属性
    
    action参数有三种写法
        1.什么都不写 默认往当前页面的url地址提交
        2.只写路由后缀(******)
        <form action="/login/" method="post">
        3.写全路径
            <form action="https://www.baidu.com" method="post"> 
    # 数据后端获取
    
    #前端
                <form action="" method="post">
                    <p>username:<input type="text" class="form-control" name="username"></p>
                    <p>password:<input type="password" class="form-control" name="password"></p>
                    <p>篮球<input type="checkbox" name="xxx" value="basketball"></p>
                    <p>足球<input type="checkbox" name="xxx" value="football"></p>
                    <p>冰球<input type="checkbox" name="xxx" value="ice"></p>
                    <input type="submit" class="btn btn-success pull-right">
                </form>
    # views.py:获取访问login页面的method以及post提交的数据
    def login(request):
        print(request.method) # 获取当前请求方式
        if request.method == 'POST':
            # 获取post请求提交的数据
            print(request.POST)
            # get请求默认拿列表最后一个值:如-获取到2个username,取值永远拿最后一个元素
            username = request.POST.get('username')
            password = request.POST.get('password')  # 还可以在后面增加判断账号密码判断,以后通过数据库来判断传递的账号密码
         if username == "simon" and password == "123":
          return redirect("http://www.xiaohuar.com")
         return "xxxxxxx" hobby
    = request.POST.getlist('xxx') print(hobby,type(hobby)) print(username,type(username)) print(password, type(password)) return render(request,'login.html') # 结果: POST <QueryDict: {'username': ['simon'], 'password': ['123'], 'xxx': ['basketball', 'football', 'ice']}> ['basketball', 'football', 'ice'] <class 'list'> simon <class 'str'> 123 <class 'str'>
  • 相关阅读:
    zookeeper ACL(access control lists)权限控制
    zookeeper伪分布式集群搭建
    云服务器离线安装MariaDB安装步骤和解决办法
    云服务器——之Linux下安装tomcat
    云服务器之——Linux下配置JDK环境
    nginx安装与fastdfs配置--阿里云
    fastDFS 一二事
    云服务器 ECS--查找公网ip使用终端连接云服务
    springboot oauth 鉴权之——password、authorization_code鉴权
    springboot oauth 鉴权之——授权码authorization_code鉴权
  • 原文地址:https://www.cnblogs.com/yangmeichong/p/11303746.html
Copyright © 2020-2023  润新知