zoukankan      html  css  js  c++  java
  • Django(一)

    Django

    web框架的本质及自定义web框架

      所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端,基于请求做出响应,客户都先请求,服务端做出对应的响应,按照http协议的请求协议发送请求,服务端按照http协议的响应协议来响应请求,这样的网络通信,我们就可以自己实现Web框架了。

      基于socket来自己实现一个web框架,写一个web服务端,让浏览器来请求,并通过自己的服务端把页面返回给浏览器,浏览器渲染出我们想要的效果。  

    一、简单的web框架

    import socket
    
    sk = socket.socket()
    sk.bind(('127.0.0.1',8001))
    sk.listen()
    
    conn,addr = sk.accept()
    msg = conn.recv(1024)
    str_msg = msg.decode('utf-8')
    print(str_msg)
    
    conn.send(b'HTTP/1.1 200 ok 
    
    ')
    conn.send(b'hello world')
    
    conn.close()
    sk.close()

     在浏览器访问服务端:

    重启我们的代码,然后在网址中输入这个:

     浏览器发过来一堆的消息,我们给浏览器回复(响应)信息的时候,也要按照一个消息格式来写,这些都是http协议规定的,那么我们就来学习一下http协议,然后继续完善我们的web框架:

       HTTP协议:https://www.cnblogs.com/clschao/articles/9230431.html

     二、返回Html文件的web框架:

    首先写一个html文件,内容如下,名称为index.html:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    
        <style>
            h1{
                background-color: green;
                color: white;
            }
        </style>
    </head>
    <body>
    
    <h1>世界,你好!</h1>
    <img src="https://img3.chouti.com/img_1557880036293.jpg?imageView2/1/q" alt="">
    
    <script>
        alert('这是我们第一个网页')
    </script>
    
    </body>
    </html>

      准备我们的python代码,服务端程序,文件内容如下,文件名称为   返回Html文件的web框架.py :

    import socket
    sk = socket.socket()
    sk.bind(('127.0.0.1',8001))
    sk.listen()
    
    conn,addr = sk.accept()
    msg = conn.recv(1024)
    str_msg = msg.decode('utf-8')
    print('浏览器请求信息:',str_msg)
    conn.send(b'HTTP/1.1 200 ok 
    
    ')
    
    with open('index.html','rb') as f:
        data = f.read()
    conn.send(data)
    
    conn.close()
    sk.close()
    import socket
    from threading import Thread
    
    server = socket.socket()
    server.bind(('0.0.0.0',8001))
    server.listen()
    
    def communication(conn):
        #接受请求数据
        msg = conn.recv(1024).decode('utf-8')
        print(msg)
        #组合响应协议的消息格式,然后发送响应信息
        conn.send(b'HTTP/1.1 200 ok 
    
    ')
    
        #打开index.html文件,返回给前端
        with open('index.html', 'rb') as f:  #没有引入文件形式的html页面
            data = f.read()
        conn.send(data)
        conn.close()
    
    while 1:
        #接受连接
        conn, add = server.accept()
        #开启线性并发
        t = Thread(target=communication,args=(conn,))
        t.start()
    返回html文件(多线程,函数)web框架.py

    页面上输入网址看效果:css样式和js效果都有。

     

    将index.html 文件中css样式与js语句写成文件,图片网络地址改为本地地址(01.jpg):

    index.css:

    h1{
        background-color: green;
        color: white;
    }

    index.js

    alert('这是我们第一个网页') 

    index.html改为:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link rel="stylesheet" href="index.css">
        <!--<style>-->
            <!--h1{-->
                <!--background-color: green;-->
                <!--color: white;-->
            <!--}-->
        <!--</style>-->
    </head>
    <body>
    
    <h1>世界,你好!</h1>
    <img src="01.jpg" alt="">
    
    <!--<script>-->
        <!--alert('这是我们第一个网页')-->
    <!--</script>-->
    
    <script src="index.js"></script>
    </body>
    </html>

     同样使用我们之前的python程序,来看效果:

      需要将html页面需要的css、js、图片等文件也发送给浏览器就,并且这些静态文件都是浏览器单独过来请求的,其实和标签的属性有有关系,css文件是link标签的href属性:<link rel="stylesheet" href="test.css">,js文件是script标签的src属性:<script src="test.js"></script>,图片文件是img标签的src属性:<img src="meinv.png" alt="" width="100" height="100"> ,那个.ico文件是link标签的属性:<link rel="icon" href="wechat.ico">,其实这些属性都会在页面加载的时候,单独到自己对应的属性值里面取请求对应的文件数据,而且我们如果在值里面写的都是自己本地的路径,那么都会来自己的本地路径来找,如果我们写的是相对路径,就会到我们自己的网址+文件名称,这个路径来找它需要的文件,所以我们只需要将这些请求做一些响应,将对应的文件数据相应给浏览器就可以了!

     三、返回静态文件的高级web框架

       服务端程序:

    import socket
    
    sk = socket.socket()
    sk.bind(('127.0.0.1',8001))
    sk.listen()
    
    while 1:
        conn,addr = sk.accept()
        msg = conn.recv(1024)
        str_msg = msg.decode('utf-8')
        path = str_msg.split('
    ')[0].split(' ')[1]
        conn.send(b'HTTP/1.1 200 ok 
    
    ')
    
        if path == '/':
            print(msg.decode('utf-8'))
            with open('index.html','rb') as f:
                data = f.read()
            conn.send(data)
            conn.close()
        elif path == '/01.jpg':
            with open('01.jpg','rb') as f:
                pic_data = f.read()
            conn.send(pic_data)
            conn.close()
        elif path == '/index.css':
            with open('index.css','rb') as f:
                css_data = f.read()
            conn.send(css_data)
            conn.close()
    
        elif path == '/wechat.ico':
            with open('wechat.ico','rb') as f:
                ico_data = f.read()
            conn.send(ico_data)
            conn.close()
    
        elif path == '/index.js':
            with open('index.js','rb') as f:
                js_data = f.read()
            conn.send(js_data)
            conn.close()

      index.html:添加了<link rel="icon" href="wechat.ico">属性

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link rel="stylesheet" href="index.css">
        <link rel="icon" href="wechat.ico">
        <!--<style>-->
            <!--h1{-->
                <!--background-color: green;-->
                <!--color: white;-->
            <!--}-->
        <!--</style>-->
    </head>
    <body>
    
    <h1>世界,你好!</h1>
    <img src="01.jpg" alt="">
    
    <!--<script>-->
        <!--alert('这是我们第一个网页')-->
    <!--</script>-->
    
    <script src="index.js"></script>
    </body>
    </html>

    import socket
    from threading import Thread
    
    server = socket.socket()
    server.bind(('0.0.0.0',8001))
    server.listen()
    
    def communication(conn):
        msg = conn.recv(1024).decode('utf-8')
        print(msg)
        path = msg.split('
    ')[0].split(' ')[1]
        print(path)
        #针对不同的请求路径,返回不同的文件
        if path =='/':
            conn.send(b'HTTP/1.1 200 ok 
    k1:v1
    
    ')
            with open('index.html', 'rb') as f:
                data = f.read()
            conn.send(data)
            conn.close()
        elif path =='/index.css':
            conn.send(b'HTTP/1.1 200 ok 
    k1:v1
    
    ')
            with open('index.css', 'rb') as f:
                data = f.read()
            conn.send(data)
            conn.close()
        elif path =='/index.js':
            conn.send(b'HTTP/1.1 200 ok 
    k1:v1
    
    ')
            with open('index.js', 'rb') as f:
                data = f.read()
            conn.send(data)
            conn.close()
        elif path =='/wechat.ico':
            conn.send(b'HTTP/1.1 200 ok 
    k1:v1
    
    ')
            with open('wechat.ico', 'rb') as f:
                data = f.read()
            conn.send(data)
            conn.close()
    
        elif path =='/01.jpg':
            conn.send(b'HTTP/1.1 200 ok 
    k1:v1
    
    ')
            with open('01.jpg', 'rb') as f:
                data = f.read()
            conn.send(data)
            conn.close()
    
    while 1:
        conn, add = server.accept()
        t = Thread(target=communication,args=(conn,))
        t.start()
    进阶版返回静态文件的高级web框架.py

    四:函数多线程版返回静态文件的web框架

    静态文件使用:index.html , index.css , index.js , 01.jpg , wechat.ico

    python代码:

    import socket
    from threading import Thread
    
    server = socket.socket()
    server.bind(('127.0.0.1',8001))
    server.listen()
    
    def html(conn):
        conn.send(b'HTTP/1.1 200 ok 
    
    ')
        with open('index.html', 'rb') as f:
            data = f.read()
        conn.send(data)
        conn.close()
    def css(conn):
        conn.send(b'HTTP/1.1 200 ok 
    
    ')
        with open('index.css','rb') as f:
            data = f.read()
        conn.send(data)
        conn.close()
    
    def js(conn):
        conn.send(b'HTTP/1.1 200 ok 
    
    ')
        with open('index.js', 'rb') as f:
            data = f.read()
        conn.send(data)
        conn.close()
    
    def ico(conn):
        conn.send(b'HTTP/1.1 200 ok 
    
    ')
        with open('wechat.ico','rb') as f:
            data = f.read()
        conn.send(data)
        conn.close()
    def jpg(conn):
        conn.send(b'HTTP/1.1 200 ok 
    
    ')
        with open('01.jpg', 'rb') as f:
            data = f.read()
        conn.send(data)
        conn.close()
    
    urlpatterns = [
        ('/',html),
        ('/index.css',css),
        ('/index.js',js),
        ('/wechat.ico',ico),
        ('/01.jpg',jpg),
    ]
    
    
    def communication(conn):
        msg = conn.recv(1024).decode('utf-8')
        print(msg)
        path = msg.split('
    ')[0].split(' ')[1]
        print(path)
        #针对不同的请求路径,返回不同的文件
        for urlpattern in urlpatterns:
            if urlpattern[0] == path:
                # urlpattern[1](conn)
                # 多线程执行函数
                t = Thread(target=urlpattern[1],args=(conn,))
                t.start()
    
        # if path =='/':
        #     html(conn)
        # elif path =='/index.css':
        #     css(conn)
        # elif path =='/index.js':
        #     js(conn)
        # elif path =='/wechat.ico':
        #     ico(conn)
        # elif path =='/01.jpg':
        #     jpg(conn)
    
    while 1:
        conn, add = server.accept()
        t = Thread(target=communication,args=(conn,))
        t.start()

    五、返回不同html页面的web框架

    静态文件使用:index.html , index.css , index.js , 01.jpg , wechat.ico

    添加返回的页面 home.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <h1>首页</h1>
    <h1>time</h1>
    
    </body>
    </html>

    python代码:

    import socket
    from threading import Thread
    
    server = socket.socket()
    server.bind(('0.0.0.0',8001))
    server.listen()
    
    def html(conn):
        conn.send(b'HTTP/1.1 200 ok 
    
    ')
        with open('index.html', 'rb') as f:
            data = f.read()
        conn.send(data)
        conn.close()
    def css(conn):
        conn.send(b'HTTP/1.1 200 ok 
    
    ')
        with open('index.css', 'rb') as f:
            data = f.read()
        conn.send(data)
        conn.close()
    
    def js(conn):
        conn.send(b'HTTP/1.1 200 ok 
    
    ')
        with open('index.js', 'rb') as f:
            data = f.read()
        conn.send(data)
        conn.close()
    
    def ico(conn):
        conn.send(b'HTTP/1.1 200 ok 
    
    ')
        with open('wechat.ico', 'rb') as f:
            data = f.read()
        conn.send(data)
        conn.close()
    def jpg(conn):
        conn.send(b'HTTP/1.1 200 ok 
    
    ')
        with open('01.jpg', 'rb') as f:
            data = f.read()
        conn.send(data)
        conn.close()
    
    def home(conn):
        conn.send(b'HTTP/1.1 200 ok 
    
    ')
        with open('home.html', 'rb') as f:
            data = f.read()
        conn.send(data)
        conn.close()
    
    urlpatterns = [
        ('/',html),
        ('/index.css',css),
        ('/index.js',js),
        ('/wechat.ico',ico),
        ('/01.jpg',jpg),
        ('/home.html',home),
    ]
    
    
    def communication(conn):
        msg = conn.recv(1024).decode('utf-8')
        # print(msg)
        path = msg.split('
    ')[0].split(' ')[1]
    
        #针对不同的请求路径,返回不同的文件
        for urlpattern in urlpatterns:
            # print(path)
            if urlpattern[0] == path:
                # urlpattern[1](conn)
                # 多线程执行函数
                t = Thread(target=urlpattern[1],args=(conn,))
                t.start()
    
    while 1:
        conn, add = server.accept()
        t = Thread(target=communication,args=(conn,))
        t.start()

    六、返回动态l页面的web框架

    静态文件使用:index.html , index.css , index.js , 01.jpg , wechat.ico ,home.html

    python 代码:

    import time
    import socket
    from threading import Thread
    
    server = socket.socket()
    server.bind(('0.0.0.0',8001))
    server.listen()
    
    def html(conn):
        conn.send(b'HTTP/1.1 200 ok 
    
    ')
        with open('index.html','rb') as f:
            data = f.read()
        conn.send(data)
        conn.close()
    
    def css(conn):
        conn.send(b'HTTP/1.1 200 ok 
    
    ')
        with open('index.css','rb') as f:
            data = f.read()
        conn.send(data)
        conn.close()
    
    def js(conn):
        conn.send(b'HTTP/1.1 200 ok 
    
    ')
        with open('index.js','rb') as f:
            data = f.read()
        conn.send(data)
        conn.close()
    
    def ico(conn):
        conn.send(b'HTTP/1.1 200 ok 
    
    ')
        with open('wechat.ico','rb') as f:
            data = f.read()
        conn.send(data)
        conn.close()
    
    def jpg(conn):
        conn.send(b'HTTP/1.1 200 ok 
    
    ')
        with open('01.jpg', 'rb') as f:
            data = f.read()
        conn.send(data)
        conn.close()
    
    def home(conn):
        conn.send(b'HTTP/1.1 200 ok 
    
    ')
        current_time = str(time.time())
        with open('home.html','r',encoding='utf-8') as f:
            data = f.read()
            data = data.replace('time',current_time)
        conn.send(data.encode('utf-8'))
        conn.close()
    
    urlpatterns = [
        ('/',html),
        ('/index.css',css),
        ('/index.js',js),
        ('/favicon.ico',ico),
        ('/01.jpg',jpg),
        ('/home.html',home),
    ]
    
    def communication(conn):
        msg = conn.recv(1024).decode('utf-8')
        # print(msg)
        path = msg.split('
    ')[0].split(' ')[1]
    
        #针对不同的请求路径,返回不同的文件
        for urlpattern in urlpatterns:
            # print(path)
            if urlpattern[0] == path:
                # urlpattern[1](conn)
                # 多线程执行函数
                t = Thread(target=urlpattern[1],args=(conn,))
                t.start()
    
    while 1:
        conn, add = server.accept()
        t = Thread(target=communication,args=(conn,))
        t.start()

     

    七、wsgiref模块版web框架

       wsgiref模块其实是将整个请求信息给封装了起来,不需要你自己处理了,假如它将所有请求信息封装成了一个叫做request的对象,那么你直接request.path就能获取到用户这次请求的路径,request.method就能获取到本次用户请求的请求方式(get还是post)等,那这个模块用起来,我们再写web框架就简单了很多。

       对于真实开发中的python web程序来说,一般会分为两部分:服务器程序和应用程序。

       服务器程序负责对socket服务器进行封装,并在请求到来时,对请求的各种数据进行整理。

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

       这样,服务器程序就需要为不同的框架提供不同的支持。这样混乱的局面无论对于服务器还是框架,都是不好的。对服务器来说,需要支持各种不同框架,对框架来说,只有支持它的服务器才能被开发出的应用使用。最简单的Web应用就是先把HTML用文件保存好,用一个现成的HTTP服务器软件,接收用户请求,从文件中读取HTML,返回。如果要动态生成HTML,就需要把上述步骤自己来实现。不过,接受HTTP请求、解析HTTP请求、发送HTTP响应都是苦力活,如果我们自己来写这些底层代码,还没开始写动态HTML呢,就得花个把月去读HTTP规范。

              正确的做法是底层代码由专门的服务器软件实现,我们用Python专注于生成HTML文档。因为我们不希望接触到TCP连接、HTTP原始请求和响应格式,所以,需要一个统一的接口协议来实现这样的服务器软件,让我们专心用Python编写Web业务。

       这时候,标准化就变得尤为重要。我们可以设立一个标准,只要服务器程序支持这个标准,框架也支持这个标准,那么他们就可以配合使用。一旦标准确定,双方各自实现。这样,服务器可以支持更多支持标准的框架,框架也可以使用更多支持标准的服务器。

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

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

    from wsgiref.simple_server import make_server
    # wsgiref本身就是个web框架,提供了一些固定的功能(请求和响应信息的封装,不需要我们自己写原生的socket了也不需要咱们自己来完成请求信息的提取了,提取起来很方便)
    #函数名字随便起
    def application(environ, start_response):
        '''
        :param environ: 是全部加工好的请求信息,加工成了一个字典,通过字典取值的方式就能拿到很多你想要拿到的信息
        :param start_response: 帮你封装响应信息的(响应行和响应头),注意下面的参数
        :return:
        '''
        start_response('200 OK', [('Content-Type', 'text/html'),('k1','v1')])
        print(environ)
        print(environ['PATH_INFO'])  #输入地址127.0.0.1:8000,这个打印的是'/',输入的是127.0.0.1:8000/index,打印结果是'/index'
        return [b'<h1>Hello, web!</h1>']
    
    httpd = make_server('127.0.0.1', 8080, application)
    
    print('Serving HTTP on port 8080...')
    # 开始监听HTTP请求:
    httpd.serve_forever()

     简单wsgiref模块版web框架:

     静态文件使用:index.html , home.html

    import time
    from wsgiref.simple_server import make_server
    
    def app(environ,start_response):
        start_response('200 OK', [('Content-Type', 'text/html'), ('k1', 'v1')])
        print(environ)
        path = environ['PATH_INFO']
    
        for urlpattern in urlpatterns:
            print(path)
            if urlpattern[0] == path:
                ret = urlpattern[1]()
                return ret
    
    def html():
        with open('index.html', 'rb') as f:
            data = f.read()
        return [data]
    
    def home():
        current_time = str(time.time())
        with open('home.html', 'r',encoding='utf-8') as f:
            data = f.read()
            data = data.replace('time',current_time).encode('utf-8')
        return [data]
    
    urlpatterns = [
        ('/',html),
        ('/home.html',home),
    ]
    
    httpd = make_server('127.0.0.1', 8001, app)
    httpd.serve_forever()

    一个完整的web项目,用户登录认证的项目,需要连接数据库,在mysql数据库里面准备一些表和数据:

    mysql> create database day53;
    Query OK, 1 row affected (0.12 sec)
    
    mysql> use day53;
    Database changed
    mysql> create table userinfo(id int primary key auto_increment,username char(20) not null unique,password char(20) not null);
    Query OK, 0 rows affected (0.36 sec)
    
    mysql> insert into userinfo(username,password) values('xu','123'),('wu','456');
    Query OK, 2 rows affected (0.17 sec)
    Records: 2  Duplicates: 0  Warnings: 0
    
    mysql> select * from userinfo;
    +----+----------+----------+
    | id | username | password |
    +----+----------+----------+
    |  1 | xu       | 123      |
    |  2 | wu       | 456      |
    +----+----------+----------+
    2 rows in set (0.00 sec)

    python服务端代码(主逻辑代码):

    from urllib.parse import parse_qs
    from wsgiref.simple_server import make_server
    import webauth
    
    def application(environ, start_response):
    
        start_response('200 OK', [('Content-Type', 'text/html')])
        # print(environ)
        # print(environ['PATH_INFO'])
        path = environ['PATH_INFO']
        # 用户获取login页面的请求路径
        if path == '/login':
            with open('login.html','rb') as f:
                data = f.read()
        # 针对form表单提交的auth路径,进行对应的逻辑处理
        elif path == '/auth/':
            #登陆认证
            #1.获取用户输入的用户名和密码
    
            #2.去数据库做数据的校验,查看用户提交的是否合法
            # user_information = environ['']
            if environ.get("REQUEST_METHOD") == "POST":
                # 获取请求体数据的长度,因为提交过来的数据需要用它来提取,注意POST请求和GET请求的获取数据的方式不同
                try:
                    request_body_size = int(environ.get('CONTENT_LENGTH', 0))
                except (ValueError):
                    request_body_size = 0
                # POST请求获取数据的方式
                request_data = environ['wsgi.input'].read(request_body_size)
                print('>>>>>',request_data) # >>>>> b'username=chao&password=123',是个bytes类型数据
                print('?????',environ['QUERY_STRING'])#????? 空的,因为post请求只能按照上面这种方式取数据
                # parse_qs可以帮我们解析数据
                re_data = parse_qs(request_data.decode('utf-8')) #将bytes类型数据转码
                print('拆解后的数据',re_data)  #拆解后的数据 {'username': ['wu'], 'password': ['456']}
                username = re_data['username'][0]
                password = re_data['password'][0]
                print(username,password)
                # 进行验证
                status = webauth.auth(username,password)
                if status:
                    # 3.将相应内容返回
                    with open('success.html','rb') as f:
                        data = f.read()
                else:
                    data = b'auth error'
    
            if environ.get("REQUEST_METHOD") == "GET":
                # GET请求获取数据的方式,只能按照这种方式取
                print('?????',environ['QUERY_STRING']) #????? username=xu&password=123,是个字符串类型数据
                request_data = environ['QUERY_STRING']
                print('>>>>request_data', request_data)
                # parse_qs可以帮我们解析数据
                re_data = parse_qs(request_data)
                print('拆解后的数据', re_data)
                username = re_data['username'][0]
                password = re_data['password'][0]
                print(username,password)
                # 进行验证
                status = webauth.auth(username,password)
                if status:
                    # 3.将相应内容返回
                    with open('success.html','rb') as f:
                        data = f.read()
                else:
                    data = b'auth error'
                # 不管是post还是get请求都不能直接拿到数据,拿到的数据还需要我们来进行分解提取,所以我们引入urllib模块来帮我们分解
         
        else:
            data = b'sorry 404!,not found the page'
        return [data]
    
    httpd = make_server('127.0.0.1', 8001, application)
    print('Serving HTTP on port 8001...')
    # 开始监听HTTP请求:
    httpd.serve_forever()

    登陆页面 login.html文件:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <!--form标签中 method属性可以等于get-->
    <form action="http://127.0.0.1:8001/auth/" method="post">
        用户名<input type="text" name="username">
        密码 <input type="password" name="password">
        <input type="submit">
    </form>
    
    </body>
    </html>

    用户验证 webauth.py文件:

    def auth(username,password):
        import pymysql
        conn = pymysql.connect(
            host='127.0.0.1',
            port=3306,
            user='root',
            password='123',
            database='day53',
            charset='utf8'
        )
        print('userinfo',username,password)
        cursor = conn.cursor(pymysql.cursors.DictCursor)
    
        sql = 'select * from userinfo where username=%s and password=%s;'
        res = cursor.execute(sql, [username, password])
    
        if res:
            return True
        else:
            return False

    用户登陆成功跳转 success.html文件:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    
    </head>
    <body>
    
    <h1>恭喜登陆成功!</h1>
    
    </body>
    </html>

    一个比较low的文件配置版web框架:

     1.pycharm创建userinfo表格:

    #创建表,插入数据
    def createtable():
        import pymysql
        conn = pymysql.connect(
            host='127.0.0.1',
            port=3306,
            user='root',
            password='123',
            database='day53',
            charset='utf8'
        )
        cursor = conn.cursor(pymysql.cursors.DictCursor)
        sql = '''
            -- 创建表
            create table userinfo(id int primary key auto_increment,username char(20) not null unique,password char(20) not null);
            -- 插入数据
            insert into userinfo(username,password) values('chao','666'),('sb1','222');
        '''
        cursor.execute(sql)
        conn.commit()
        cursor.close()
        conn.close()

    2.框架主体:

    from urls import urlpatterns
    from wsgiref.simple_server import make_server
    
    #这个文件里面是框架的主体内容
    def application(environ, start_response):
        start_response('200 OK', [('Content-Type', 'text/html')])
        path = environ['PATH_INFO']
        for url_tuple in urlpatterns:
            if url_tuple[0] == path:
                data = url_tuple[1](environ) #environ要传进去,因为处理逻辑里面可能要用
                break
            else:
                data = b'sorry 404!,not found the page'
        return [data]
            #注意昂,我们如果直接返回中文,没有给浏览器指定编码格式,默认是gbk,所以我们需要gbk来编码一下,浏览器才能识别
            # data='登陆成功!'.encode('gbk')
    
    httpd = make_server('127.0.0.1', 8001, application)
    
    print('Serving HTTP on port 8001...')
    # 开始监听HTTP请求:
    httpd.serve_forever()
    
    #整个框架写好了,那么我们将来想添加一些新的功能,比如说有人想在网址里面输入http://127.0.0.1:8001/timer 来查看当前时间,你只需要两步,写一个url映射关系,写一个应对的处理函数就搞定了,有了框架就不需要你在重新写一遍这所有的逻辑了,简单两步搞定新功能

    3.urls文件:

    from views import login,auth,favicon,index,timer
    
    #url与视图函数的对应关系
    urlpatterns=[
        ('/login',login),
        ('/auth/',auth),
        ('/favicon.ico',favicon),
        ('/',index),
        ('/timer',timer),
    
    ]

    4.views文件:

    import datetime
    import webauth
    from urllib.parse import parse_qs
    
    def login(environ):
        with open('templates/login.html', 'rb') as f:
            data = f.read()
        return data
    
    def auth(environ):
        # 登陆认证
        # 1.获取用户输入的用户名和密码
    
        # 2.去数据库做数据的校验,查看用户提交的是否合法
        # user_information = environ['']
        if environ.get("REQUEST_METHOD") == "POST":
            # 获取请求体数据的长度,因为提交过来的数据需要用它来提取,注意POST请求和GET请求的获取数据的方式不同
            try:
                request_body_size = int(environ.get('CONTENT_LENGTH', 0))
            except (ValueError):
                request_body_size = 0
            # POST请求获取数据的方式
            request_data = environ['wsgi.input'].read(request_body_size)
            print('>>>>>', request_data)  # >>>>> b'username=chao&password=123',是个bytes类型数据
            print('?????', environ['QUERY_STRING'])  # ????? 空的,因为post请求只能按照上面这种方式取数据
            # parse_qs可以帮我们解析数据
            re_data = parse_qs(request_data.decode('utf-8'))  # 将bytes类型数据转码
            print('拆解后的数据', re_data)  # 拆解后的数据 {'username': ['wu'], 'password': ['456']}
            username = re_data['username'][0]
            password = re_data['password'][0]
            print(username, password)
            # 进行验证
            status = webauth.auth(username, password)
            if status:
                # 3.将相应内容返回
                with open('success.html', 'rb') as f:
                    data = f.read()
            else:
                data = b'auth error'
        if environ.get("REQUEST_METHOD") == "GET":
            # GET请求获取数据的方式,只能按照这种方式取
            print('?????', environ['QUERY_STRING'])  # ????? username=chao&password=123,是个字符串类型数据
            request_data = environ['QUERY_STRING']
    
            # parse_qs可以帮我们解析数据
            re_data = parse_qs(request_data)
            print('拆解后的数据', re_data)  # 拆解后的数据 {'password': ['123'], 'username': ['chao']}
            username = re_data['username'][0]
            password = re_data['password'][0]
            print(username, password)
            # 进行验证:
            status = webauth.auth(username, password)
            if status:
                # 3.将相应内容返回
                with open('templates/websuccess.html', 'rb') as f:
                    data = f.read()
            else:
                data = b'auth error'
        return data
    
    def favicon(environ):
        with open('wechat.ico','rb') as f:
            data = f.read()
        return data
    
    def index(environ):
        with open('templates/index.html','rb') as f:
            data = f.read()
        return data
    
    #查看当前时间的
    def timer(environ):
        data = str(datetime.datetime.now()).encode('utf-8')
        return data

    5.用户名密码验证 webauth文件:

    #对用户名和密码进行验证
    def auth(username,password):
        import pymysql
        conn = pymysql.connect(
            host='127.0.0.1',
            port=3306,
            user='root',
            password='123',
            database='day53',
            charset='utf8'
        )
        print('userinfo',username,password)
        cursor = conn.cursor(pymysql.cursors.DictCursor)
        sql = 'select * from userinfo where username=%s and password=%s;'
        res = cursor.execute(sql, [username, password])
        if res:
            return True
        else:
            return False

    6.templates 文件夹下html文件:

    index.html:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <a href="http://127.0.0.1:8001/login">请登录</a>
    
    </body>
    </html>

    login.html:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <!--如果form表单里面的action什么值也没给,默认是往当前页面的url上提交你的数据,所以我们可以自己指定数据的提交路径-->
    <!--<form action="http://127.0.0.1:8001/auth/" method="post">-->
    <form action="http://127.0.0.1:8001/auth/" method="get">
        用户名<input type="text" name="username">
        密码 <input type="password" name="password">
        <input type="submit">
    </form>
    
    </body>
    </html>

    websuccess.html:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <style>
            h1{
                color:red;
            }
        </style>
    </head>
    <body>
    <h1>恭喜你登陆成功!</h1>
    
    </body>
    </html>

    模板渲染JinJa2

      上面的代码实现了一个简单的动态页面(字符串替换),我完全可以从数据库中查询数据,然后去替换我html中的对应内容(专业名词叫做模板渲染,你先渲染一下,再给浏览器进行渲染),然后再发送给浏览器完成渲染。 这个过程就相当于HTML模板渲染数据。 本质上就是HTML内容中利用一些特殊的符号来替换要展示的数据。 我这里用的特殊符号是我定义的,其实模板渲染有个现成的工具: jinja2

     下载:在cmd命令提示符中输入或者pycharm中terminal

    pip install jinja2

    来一个html文件,index,html,内容如下:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h1>姓名:{{name}}</h1>
        <h1>爱好:</h1>
        <ul>
            {% for hobby in hobby_list %}
            <li>{{hobby}}</li>
            {% endfor %}
        </ul>
    </body>
    </html>

    使用jinja2渲染index2.html文件,创建一个python文件:

    from wsgiref.simple_server import make_server
    from jinja2 import Template

    def index():
    with open("index.html", "r",encoding='utf-8') as f:
    data = f.read()
    template = Template(data) # 生成模板文件
    ret = template.render({"name": "于谦", "hobby_list": ["抽烟", "喝酒","烫头"]}) # 把数据填充到模板里面
    return [bytes(ret, encoding="utf8"), ]

    # 定义一个url和函数的对应关系
    URL_LIST = [
    ("/index", index),
    ]

    def run_server(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ]) # 设置HTTP响应的状态码和头信息
    url = environ['PATH_INFO'] # 取到用户输入的url
    func = None # 将要执行的函数
    for i in URL_LIST:
    if i[0] == url:
    func = i[1] # 去之前定义好的url列表里找url应该执行的函数
    break
    if func: # 如果能找到要执行的函数
    return func() # 返回函数的执行结果
    else:
    return [bytes("404没有该页面", encoding="utf8"), ]


    if __name__ == '__main__':
    httpd = make_server('', 8001, run_server)
    print("Serving HTTP on port 8001...")
    httpd.serve_forever()

     

     从数据库中查询数据,来填充页面

    使用pymysql连接数据库:

    conn = pymysql.connect(host="127.0.0.1", port=3306, user="root", passwd="xxx", db="xxx", charset="utf8")
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    cursor.execute("select name, age, department_id from userinfo")
    user_list = cursor.fetchall()
    cursor.close()
    conn.close()

     创建一个测试的user表:

    CREATE TABLE user(
      id int auto_increment PRIMARY KEY,
      name CHAR(10) NOT NULL,
      hobby CHAR(20) NOT NULL
    )engine=innodb DEFAULT charset=UTF8;

    模板的原理就是字符串替换,我们只要在HTML页面中遵循jinja2的语法规则写上,其内部就会按照指定的语法进行相应的替换,从而达到动态的返回内容。

  • 相关阅读:
    uniapp开发注意事项
    uniapp生成海报带二维码及保存
    严格模式的this
    数据类型
    短路特性
    第九周程序改错
    矩阵转置
    二分法求根
    三天打鱼两天晒网
    LeetCode7
  • 原文地址:https://www.cnblogs.com/Xiao_Xu/p/10868840.html
Copyright © 2011-2022 走看看