zoukankan      html  css  js  c++  java
  • Django框架简介

     web框架本质

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

    import socket
    
    
    server = socket.socket()
    server.bind(('127.0.0.1',8080))
    server.listen(5)
    
    while True:
        conn, addr = server.accept()
        data = conn.recv(1024)
        print(data)  # 将浏览器发来的消息打印出来
        conn.send(b"OK")
        conn.close()

    可以说Web服务本质上都是在这十几行代码基础上扩展出来的。

    用户的浏览器一输入网址,会给服务端发送数据,那浏览器会发送什么数据?怎么发?这个谁来定? 你这个网站是这个规定,他那个网站按照他那个规定,这互联网还能玩么?

    所以,必须有一个统一的规则,让大家发送消息、接收消息的时候有个格式依据,不能随便写。

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

    HTTP协议主要规定了客户端和服务器之间的通信格式,那HTTP协议是怎么规定消息格式的呢?

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

    输出结果:

    """
    请求首行
    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.80 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
    
    
    
    请求体
    ......
    """

    要想让我们自己写的web server端正经起来,必须要让我们的Web server在给客户端回复消息的时候按照HTTP协议的规则加上响应状态行,这样我们就实现了一个正经的Web框架了

    import socket
    
    
    server = socket.socket()
    server.bind(('127.0.0.1',8080))
    server.listen(5)
    
    while True:
        conn, addr = server.accept()
        data = conn.recv(1024)
        #给回复的信息加上响应状态行
        conn.send(b'HTTP/1.1 200 OK
    
    ')
        conn.send(b'hello world')
        print(data)

    我们通过十几行代码简单地演示了web 框架的本质。

    接下来就让我们继续完善我们的自定义web框架吧!

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

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

    我们可以从请求相关数据里面拿到请求URL的路径,然后拿路径做一个判断...

    import socket
    
    
    server = socket.socket()
    server.bind(('127.0.0.1',8080))
    server.listen(5)
    
    while True:
        conn, addr = server.accept()
        data = conn.recv(1024)
        conn.send(b'HTTP/1.1 200 OK
    
    ')
        data = data.decode('utf-8')  # 把从浏览器那里收到的字节类型的数据转换成字符串
        # print(data)
        target_url = data.split('
    ')[0].split(' ')[1]  #按
    分割
        # 根据不同的路径返回不同内容
        if target_url == '/index':
            # conn.send(b'index')
            with open(r'D:demo.html','rb') as f:
                conn.send(f.read())
        elif target_url == '/login':
            conn.send(b'login')
        else:
            conn.send(b'404 error')
        conn.close()

    基于wsgiref模块:

    根据功能的不同拆分成不同的文件,用户在浏览器窗口输入url之所以能够获取到相应的资源,是因为后端早已经开设了相应的资源接口 

    基于wsgiref模块以及文件拆分的特点:

    若要开设新的资源
    1.先在urls文件中写url与函数的对应关系
    2.再去views文件中写对应的函数

    urls.py:路由与视图函数的对应关系
    views.py:里面就是放的一堆视图函数(视图函数可以是函数也可以是类)
    templates文件夹:里面放的就是一堆html文件(模板文件夹)

    动静态网页

    静态网页:数据是写死的,万年不变

    动态网页:数据是动态获取的,如获取当前时间,从数据库中取数据

    jinja2模块 

    提供了一个可以在html页面上书写类似于python后端的代码 来操作数据(模板语法) ,flask框架模板语法使用的就是jinja2模块,所以你只要下了flask框架 就会自动下载jinja2 

    模板语法(jinja2模板语法非常贴近python语法 但是并不是所有的框架使用的都是jinja模板语法)

    {{ xxx }}
    <p>{{xxx.username}}</p>
    <p>{{xxx['password']}}</p>
    <p>{{xxx.get('hobby')}}</p>
    <p>{{xxx.get('hobby')[0]}}</p>
    <p>{{xxx.get('hobby').1}}</p>
    View Code
    {%for user_dict in xxx %}
        <tr>
            <td>{{ user_dict.id }}</td>
            <td>{{ user_dict.name }}</td>
            <td>{{ user_dict.hobby }}</td>
        </tr>
    {% endfor %}
    View Code

    基于wsgiref模块、jinjia2实现web框架

    from views import *
    
    urls = [
        ('/index',index),
        ('/login',login),
        ('/xxx',xxx),
        ('/get_time',get_time),
        ('/get_user',get_user),
        ('/get_info',get_info)
    ]
    urls.py
    def index(env):
        return 'index'
    
    def login(env):
        return 'login'
    
    def error(env):
        return '404 error'
    
    def xxx(env):
        return 'xxx'
    
    import time
    def get_time(env):
        # 该函数需要返回一个html页面
        current_time = time.strftime('%Y-%m-%d %X')
        # 文件操作 读取html文件
        with open(r'F:python	emplates2 get_time.html','r',encoding='utf-8') as f:
            data = f.read()  # html文件内容  字符串
        data = data.replace('gfdgsffsda',current_time)  # 利用字符串的替换
        return data
    
    from jinja2 import Template
    def get_user(env):
        user_dict = {'username':'jason','password':123,'hobby':['read','study','run']}
        with open(r'F:python	emplates4 get_info.html','r',encoding='utf-8') as f:
            data = f.read()
        temp = Template(data)
        res = temp.render(xxx=user_dict)  # 将user_dict传递给html页面 在页面上通过变量名xxx就能够获取到user_dict
        return res
    
    
    import pymysql
    def get_info(env):
        conn = pymysql.connect(
            host = '127.0.0.1',
            port = 3306,
            user = 'root',
            password = '123',
            database = 'day49',
            charset = 'utf8',
            autocommit = True
        )
        cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
        sql = "select * from userinfo"
        cursor.execute(sql)
        data = cursor.fetchall()  # [{},{},{}]
        # 将列表套字典的结构数据 直接传递给html页面
        with open(r'D:get_info.html','r',encoding='utf-8') as f:
            res = f.read()
        # 利用jinja2模块
        tmp = Template(res)
        # 利用对象的render方法 将数据直接传递给html页面
        res = tmp.render(xxx=data)
        return res
    views.py
    from wsgiref.simple_server import make_server
    from views import *
    from urls import urls
    
    
    def run(env,response):
        """
        :param env: 请求相关的所有数据
        :param response: 响应相关的所有数据
        :return: 浏览器能够接受的内容
        """
        response('200 OK',[])
        # print(env)  # env是一个大字典  里面的PATH_INFO参数就是用户输入的后缀
        target_url = env.get('PATH_INFO')
        # if target_url == '/index':
        #     # 一堆逻辑判断
        #     return [b'index']
        # elif target_url == '/login':
        #     return [b'login']
        # 先定义一个变量 用来存储可能匹配到的函数名
        func = None
        # 1 for循环获取一个个的url与函数对应关系的元组
        for url in urls:  # url = (),(),()
            # 2 判断当前用户访问的url与元组第一个元素是否一致
            if target_url == url[0]:
                # 3 如果相等 说明有对应的后端逻辑代码 将匹配到的函数名赋值给func
                func = url[1]
                # 4 一旦用户匹配上了响应的url 应该立刻结束当前for循环了 因为再循环就没有意义
                break
        # 针对func是否有值 还需要判断
        if func:
            # 匹配上了  加括号直接调用
            res = func(env)
        else:
            # 匹配404逻辑代码
            res = error(env)
        return [res.encode('utf-8')]  # 返回函数的返回值
    
    
    if __name__ == '__main__':
        # 监听127.0.0.1:8080 一旦有客户端来访问 会立刻将make_server第三个参数加括号调用执行
        server = make_server('127.0.0.1',8080,run)
        server.serve_forever()  # 启动服务端
    wsgiref

    web框架简介

    python三大主流web框架

    Django  优势:大而全,自身携带的组件和功能特别多,就类似于航空母舰。不足之处:笨重

    Flask  优势:小而精,自身携带的组件和功能特别少,就类似于游骑兵,虽然自身功能比较少,但是第三方支持该框架的模块很多如果你将flask第三方模块全部叠加起来甚至可以超过django  不足之处:受限于第三方模块 

    Tornado  异步非阻塞,天然支持高并发 甚至可以用它来开发游戏服务器

    Django框架

    Django框架注意事项:

    1. 计算机名称不能有中文 
    2. 项目文件名也不要用中文 
    3. 一个pycharm窗口就是一个单独的完整的项目 

    Django版本:

    推荐使用1.X版本里面的1.11.09~1.11.13

    安装

    pip3 install django==1.11.11

    #测试是否安装成功
    命令行输入 django-admin

    创建django项目的两种方式

    1.使用命令行创建

    创建django项目:
    django-admin startproject mysite(项目名)

    效果:创建了一个mysite的文件夹

    目录介绍
    mysite/
    ├── manage.py  # 管理文件
    └── mysite  # 项目目录
        ├── __init__.py
        ├── settings.py  # 配置
        ├── urls.py  # 路由 --> URL和函数的对应关系
        └── wsgi.py  # runserver命令就使用wsgiref模块做简单的web server
    启动Django项目:
    python manage.py runserver  # django默认的端口号是8000

    Django 若启动报错“SyntaxError: Generator expression must be parenthesized”

    报这个错很大可能是因为使用了Python3.7.0,而目前(2018-06-12)Python3.7.0和Django还有点兼容性问题。解决方案如下

    Django 启动时报错 “UnicodeEncodeError ...”

    报这个错误通常是因为计算机名为中文,改成英文的计算机名重启下电脑就可以了。

    创建具有独立功能的app
    python manage.py startapp app01  #通常情况下应该做到见名知意 

      app01
        -- migrations 文件夹
        -- __init__.py
        -- admin.py
        -- apps.py
        -- models.py
        -- tests.py
        -- views.py

    app(application)的概念

    django其实是一个专注于开发app的web框架,一个空的django项目就类似于是一所大学,app就类似于大学里面的各个学院。

    每个app其实就类似于不同的功能模块

      购物网站
        用户相关 user
          用户相关的app
        订单相关 order
          订单相关的app
        投诉相关 tousu
          投诉相关的app

    不同的功能模块推荐使用不同的app去开发,django支持多app

    Django主要文件功能
        mysite
            -mysite
                --__init__.py
                --settings.py  项目配置文件
                --urls.py      路由视图函数对应关系 项目的总路由
                --wsgi.py      
            -manage.py
    app01
    --migrations文件夹 数据库改动记录 --__init__.py --__init__.py --admin.py django后台管理 --apps.py 注册app相关 --models.py 模型类(ORM) --tests.py 测试文件 --views.py 视图函数(******)


         db.sqlite3 django自带的一个小型用于本地测试的数据库(对日期格式的数据不是很敏感)

    2.使用pycharm创建

    注意:1.使用命令行创建的django项目是不会自动创建templates模板文件夹,只能自己手动创建

    2.命令行创建的django项目不但没有templates文件夹,配置文件中也没有填写路径,而pycharm创建的会自动添加


     容易犯的错误:代码修改了始终没有效果

    1.在同一个端口起了多个服务 一直跑的是最开始的那个服务
    2.浏览器缓存问题


    解决浏览器缓存如下图

     

     补充:简化命令的方式

    项目配置文件夹注意事项:(注册)

    注意:创建app之后一定要先去setting文件中注册,在没有使用到app的一些特殊操作时(比如数据库相关),可以不用注册,但是注册后,应用的所有功能都能使用(强烈建议注册)

     

    pycharm创建的Django项目的配置文件

    命令行创建的Django项目的配置文件

     

    国际化配置(根据需要修改)

    Django能够自动重启,但是它的重启机制只要检测到你的代码有变化,则在一定的时间间隔内就会自动重启。所以有时候可能会出现 你代码还没写完就已经自动重启了

    Django基础必备三件套

    HttpResponse:返回字符串

    render:返回html页面 并可以给html页面传数据

        模板的渲染(将数据在后端按照模板语法放入html对应的位置)

    redirect:重定向

    from django.shortcuts import render,HttpResponse,redirect
    
    # Create your views here.
    def index(request):
        return HttpResponse('字符串')
    
    def login(request):
        return render(request,'templates文件夹下的html文件名',{'user_dict':{'username':'jason','password':123},'userxxx':'hello world'}))
    
    def home(request):
        # return redirect('http://www.baidu.com')
        return redirect('/index')
  • 相关阅读:
    文件处理
    集合 字符编码
    3-11作业
    win 10 在vs2017下对mpi的安装以及认识
    java中二维数组的排序
    java中Arrays的用法
    java中随机二维数组中寻找最大值并输出坐标
    用java打印图形
    面向对象object与constructor
    for each in for in 与for of
  • 原文地址:https://www.cnblogs.com/baohanblog/p/12145356.html
Copyright © 2011-2022 走看看