python项目Django(web服务)

一、  简单的web框架服务器

    创建一个python文件,内容如下,名称为test.py:

  
import socket

sk = socket.socket()
sk.bind(('127.0.0.1', 8001))
sk.listen()
conn, addr = sk.accept()
from_b_msg = conn.recv(1024)
str_msg = from_b_msg.decode('utf-8')
print("浏览器请求信息:", str_msg)
# socket是应用层和传输层之间的抽象层,每次都有协议,协议就是消息格式,那么传输层的消息格式我们不用管,因为socket帮我们搞定了,但是应用层的协议还是需要咱们自己遵守的,所以再给浏览器发送消息的时候,如果没有按照应用层的消息格式来写,那么你返回给浏览器的信息,浏览器是没法识别的。而应用层的协议就是我们的HTTP协议,所以我们按照HTTP协议规定的消息格式来给浏览器返回消息就没有问题了,关于HTTP我们会细说,首先看一下直接写conn.send(b'hello')的效果,然后运行代码,通过浏览器来访问一下,然后再看这一句conn.send(b'HTTP/1.1 200 ok \r\n\r\nhello')的效果
# 下面这句就是按照http协议来写的
# conn.send(b'HTTP/1.1 200 ok \r\n\r\nhello')
# 上面这句还可以分成下面两句来写
conn.send(b'HTTP/1.1 200 ok \r\n\r\n')
conn.send(b'hello')
View Code

二、  返回HTML文件的web框架(动态加载方式)

    img标签中的资源在网络的其他服务器上,可以直接访问, js,css文件写在当前加载的html文件中可以统一加载,属于动态加载html

  
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title><link rel="stylesheet" href="test.css">

    <!--直接写在html页面里面的css样式是直接可以在浏览器上显示的-->
    <style>
        h1{
            background-color: green;
            color: white;
        }
    </style>
</head>
<body>

<h1>hello world!</h1>
<!--直接写在html页面里面的img标签的src属性值如果是别人网站的地址(网络地址)是直接可以在浏览器上显示的-->
<img src="http://pic214.nipic.com/file/20190429/12398452_133616540089_2.jpg" alt="">
<!--如果都是网络地址,那么只要你的电脑有网,就可以看到,不需要自己在后端写对应的读取文件,返回图片文件信息的代码,因为别人的网站就做了这个事情了-->

<!--直接写在html页面里面的js操作是直接可以在浏览器上显示的-->
<script>
    alert('这是我们第一个网页')
</script>

</body>
</html>
示例

三、  简单区分区别get与post请求(form表达验证)

  
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

</head>
<body>

<!--get请求:GET提交的数据会放在URL之后,也就是请求行里面,以?分割URL和传输数据,参数之间以&相连-->
<form action="http://127.0.0.1:8001" method="get">
    用户名1 <input type="text" name="username">
    <button>提交</button>

</form>

<!--get请求:是把提交的数据放在HTTP包的请求体中-->
<form action="http://127.0.0.1:8001" method="post">
    用户名2 <input type="text" name="username">
    <button>提交</button>

</form>


</body>
</html>
示例

四、  html文件favicon图标加载

  
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>这里favicon测试</title>
    <link rel="icon" href="https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1557910698&di=afab29beb3c80b8fb692788b4b1753c7&src=http://b-ssl.duitang.com/uploads/item/201505/27/20150527235406_8GSLT.thumb.700_0.jpeg">
</head>
<body>


<script>
    alert('favicon测试:请查看title标签图标!')
</script>

</body>
</html>
示例

五、  返回HTML文件的web框架(静态加载)

当我们直接在浏览器上保存某个页面的时候,随便一个页面,我们到页面上点击右键另存为,然后存到本地的一个目录下,你会发现这个页面的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">
其实这些属性都会在页面加载的时候,单独到自己对应的属性值里面取请求对应的文件数据,而且我们如果在值里面写的都是自己本地的路径,那么都会来自己的本地路径来找
如果我们写的是相对路径,就会到我们自己的网址+文件名称,这个路径来找它需要的文件,所以我们只需要将这些请求做一些响应,将对应的文件数据相应给浏览器就可以了!

示例:

  • timg.jpg,favicon.ico文件

  • py文件的三种实现方式:

import socket
from threading import Thread

server = socket.socket()
server.bind(('127.0.0.1', 8001))
server.listen()


def communication(conn):
    client_msg = conn.recv(1024).decode('utf-8')
    # print(client_msg)
    path = client_msg.split('\r\n')[0].split(' ')[1]
    print(path)
    # 针对不同的请求路径,返回不同的文件
    if path == '/':
        conn.send(b'HTTP/1.1 200 ok \r\nk1:v1\r\n\r\n')
        with open('test1.html', 'rb') as f:
            data = f.read()
        conn.send(data)
        conn.close()
    elif path == '/index.css':
        conn.send(b'HTTP/1.1 200 ok \r\nk1:v1\r\n\r\n')
        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 \r\nk1:v1\r\n\r\n')
        with open('index.js', 'rb') as f:
            data = f.read()
        conn.send(data)
        conn.close()
    elif path == '/favicon2.ico':
        conn.send(b'HTTP/1.1 200 ok \r\nk1:v1\r\n\r\n')
        with open('favicon2.ico', 'rb') as f:
            data = f.read()
        conn.send(data)
        conn.close()
    elif path == '/timg.jpg':
        conn.send(b'HTTP/1.1 200 ok \r\nk1:v1\r\n\r\n')
        with open('timg.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()
普通方式
import socket
from threading import Thread

server = socket.socket()
server.bind(('127.0.0.1', 8001))
server.listen()


# 文件发送
def file_send(path, conn):
    conn.send(b"HTTP/1.1 200 OK \r\n\r\n")
    with open(path, "rb") as p:
        data = p.read()
    conn.send(data)
    conn.close()


# 服务端等待连接
def communication(conn):
    client_msg = conn.recv(1024).decode('utf-8')
    # print(client_msg)
    path = client_msg.split('\r\n')[0].split(' ')[1]
    print(path)
    # 针对不同的请求路径,返回不同的文件
    if path == "/":
        filepath = r"test1.html"
        file_send(filepath, conn)
    elif path == "/index.css":
        filepath = r"index.css"
        file_send(filepath, conn)
    elif path == "/index.js":
        filepath = "index.js"
        file_send(filepath, conn)
    elif path == "/timg.jpg":
        filepath = r"timg.jpg"
        file_send(filepath, conn)
    elif path == "/favicon2.ico":
        filepath = r"favicon2.ico"
        file_send(filepath, conn)


while 1:
    conn, add = server.accept()
    t = Thread(target=communication, args=(conn,))
    t.start()
函数封装
import socket
from threading import Thread

sk = socket.socket()
sk.bind(('127.0.0.1', 8001))
sk.listen()


# 加载html网页文件
def func1(conn):
    conn.send(b'HTTP/1.1 200 ok\r\n\r\n')
    with open(r"test1.html", "rb") as p:
        data = p.read()
    conn.send(data)
    conn.close()


# 加载img文件
def func2(conn):
    conn.send(b'HTTP/1.1 200 ok\r\n\r\n')
    with open(r"timg.jpg", "rb") as p:
        data = p.read()
    conn.send(data)
    conn.close()


# 加载css文件
def func3(conn):
    conn.send(b'HTTP/1.1 200 ok\r\n\r\n')
    with open(r"index.css", "rb") as p:
        data = p.read()
    conn.send(data)
    conn.close()


# 加载ico图标文件
def func4(conn):
    conn.send(b'HTTP/1.1 200 ok\r\n\r\n')
    with open(r"favicon2.ico", "rb") as p:
        data = p.read()
    conn.send(data)
    conn.close()


# 加载js文件
def func5(conn):
    conn.send(b'HTTP/1.1 200 ok\r\n\r\n')
    with open(r"index.js", "rb") as p:
        data = p.read()
    conn.send(data)
    conn.close()


# 循环开启线程,加载静态文件列表
def func(path, conn):
    for i in lst:
        if i[0] == path:
            t = Thread(target=i[1], args=(conn,))
            t.start()


# 文件加载列表
lst = [
    ('/', func1),
    ('/timg.jpg', func2),
    ('/index.css', func3),
    ('/favicon2.ico', func4),
    ('/index.js', func5),
]

# 等待连接
while True:
    conn, _ = sk.accept()
    msg = conn.recv(1024).decode("utf-8")
    # print(msg)
    path = msg.split("\n")[0].split(" ")[1]
    print(path)
    # 开启多线程,可接受多个连接请求
    Thread(target=func, args=(path, conn)).start()
并发实现

  • html文件:test1.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="index.css">
    <link rel="icon" href="favicon2.ico">
</head>
<body>
<h1>在苍茫的大海上,狂风卷集着乌云。在乌云和大海之间,海燕像黑色的闪电,在高傲地飞翔。</h1>
<img src="timg.jpg" alt="">



<script src="index.js"></script>
</body>
</html>
test1.html
• ccs文件:index.css

h1{
    background-color: red;
    color: #ffffff;
}

• js文件:index.js

alert('简单的web服务测试代码!');
css文件 + js文件

 六、  不同路径返回不同页面的web框架

import socket
sk = socket.socket()
sk.bind(("127.0.0.1", 9001))  # 绑定IP和端口
sk.listen()  # 监听


# 将返回不同的内容部分封装成函数
def index(url):
    # 读取index.html页面的内容
    with open("index.html", "r", encoding="utf8") as f:
        s = f.read()
    # 返回字节数据
    return bytes(s, encoding="utf8")


def home(url):
    with open("home.html", "r", encoding="utf8") as f:
        s = f.read()
    return bytes(s, encoding="utf8")


# 定义一个url和实际要执行的函数的对应关系
list1 = [
    ("/index/", index),
    ("/home/", home),
]

while 1:
    # 等待连接
    conn, add = sk.accept()
    data = conn.recv(8096)  # 接收客户端发来的消息
    # 从data中取到路径
    data = str(data, encoding="utf8")  # 把收到的字节类型的数据转换成字符串
    # 按\r\n分割
    data1 = data.split("\r\n")[0]
    url = data1.split()[1]  # url是我们从浏览器发过来的消息中分离出的访问路径
    conn.send(b'HTTP/1.1 200 OK\r\n\r\n')  # 因为要遵循HTTP协议,所以回复的消息也要加状态行
    # 根据不同的路径返回不同内容
    func = None  # 定义一个保存将要执行的函数名的变量
    for i in list1:
        if i[0] == url:
            func = i[1]
            break
    if func:
        response = func(url)
    else:
        response = b"404 not found!"

    # 返回具体的响应消息
    conn.send(response)
    conn.close()
示例

七、  返回动态页面的web框架

    静态页面:页面的内容都不会变化的
    动态页面:里面有动态变化的数据,而不是页面里面有动态效果

"""
根据URL中不同的路径返回不同的内容
返回HTML页面
让网页动态起来
"""

import socket
import time

sk = socket.socket()
sk.bind(("127.0.0.1", 9001))  # 绑定IP和端口
sk.listen()  # 监听


# 将返回不同的内容部分封装成函数
def index(url):
    with open("index.html", "r", encoding="utf-8") as p:  # 此处转换成字符串,实现字符串替换功能
        data = p.read()
        now = str(time.time())
        data = data.replace("@@@@", now)  # 在网页中定义好特殊符号,用动态的数据去替换提前定义好的特殊符号
    return bytes(data, encoding="utf-8")  # 转换成bytes类型


def home(url):
    with open("home.html", "rb") as p:           # 此处直接返回二进制
        data = p.read()
    return data


# 定义一个url和实际要执行的函数的对应关系
urlpatterns = [
    ("/index", index),
    ("/home", home)
]

while True:
    # 等待连接
    conn, add = sk.accept()
    data = conn.recv(1024)  # 接收客户端发来的消息
    # 从data中取到路径
    data = str(data, encoding="utf-8")  # 把收到的字节类型的数据转换成字符串
    # 按\r\n分割,再空格分割,获取访问路径
    path = data.split("\r\n")[0].split(" ")[1]
    print(path)

    conn.send(B"HTTP/1.1 200 OK\r\n\r\n")  # 因为要遵循HTTP协议,所以回复的消息也要加状态行
    # 根据不同的路径返回不同内容
    func = None  # 定义一个保存将要执行的函数名的变量
    for i in urlpatterns:
        if i[0] == path:
            func = i[1]
            break
    if func:
        response = func(path)
    else:
        response = b"404 not found!"

    # 返回具体的响应消息
    conn.send(response)
    conn.close()
示例

八、  wsgiref模块版web框架

  对于真实开发中的python web程序来说,一般会分为两部分:服务器程序和应用程序
  1、服务器程序负责对socket服务器进行封装,并在请求到来时,对请求的各种数据进行整理。
  2、应用程序则负责具体的逻辑处理。为了方便应用程序的开发,就出现了众多的Web框架,例如:Django、Flask、web.py 等。不同的框架有不同的开发方式,但是无论如何,开发出的应用程序都要和服务器程序配合,才能为用户提供服务。

WSGI(Web Server Gateway Interface)就是一种规范,它定义了使用Python编写的web应用程序与web服务器程序之间的接口格式,实现web应用程序与web服务器程序间的解耦。
常用的WSGI服务器有uwsgi、Gunicorn。而Python标准库提供的独立WSGI服务器叫wsgiref,Django开发环境用的就是这个模块来做服务器。

wsgiref模块其实就是将整个请求信息给封装了起来,就不需要你自己处理了,假如它将所有请求信息封装成了一个叫做request的对象
• request.path就能获取到用户这次请求的路径
• request.method就能获取到本次用户请求的请求方式(get还是post)等

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:9001,这个打印的是'/',输入的是127.0.0.1:8000/index,打印结果是'/index'
    return [b'<h1>Hello, web!</h1>']   # 以数组形式返回一个bytes内容


httpd = make_server("127.0.0.1", 9001, application)
print('Serving HTTP on port 8080...')
# 开始监听HTTP请求
httpd.serve_forever()
示例

九、  wsgiref模块版web框架(MVC框架)

数据库方式创建表和记录:

mysql> create database db1;
Query OK, 1 row affected (0.00 sec)

mysql> use db1;
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.23 sec)

mysql> insert into userinfo(username,password) values('chao','666'),('sb1','222');
Query OK, 2 rows affected (0.03 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> select * from userinfo;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | chao     | 666      |
|  2 | sb1      | 222      |
+----+----------+----------+
2 rows in set (0.00 sec)
View Code

通过pymysql方式创建数据库的表和记录的model.py:

#创建表,插入数据
def createtable():
    import pymysql
    conn = pymysql.connect(
        host='127.0.0.1',
        port=3306,
        user='root',
        password='1234',
        database='db1',
        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);

    '''
    sql1 = """
            -- 插入数据
        insert into userinfo(username,password) values('chao','666'),('sb1','222');
    """
    cursor.execute(sql)
    cursor.execute(sql1)

    conn.commit()
    cursor.close()
    conn.close()
View Code

服务器的框架的主体结构的manage.py:

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')



#和咱们学的socketserver那个模块很像啊
httpd = make_server('127.0.0.1', 8080, application)

print('Serving HTTP on port 8080...')
# 开始监听HTTP请求:
httpd.serve_forever()

#整个框架写好了,那么我们将来想添加一些新的功能,比如说有人想在网址里面输入http://127.0.0.1:8080/timer 来查看当前时间,你只需要两步,写一个url映射关系,写一个应对的处理函数就搞定了,有了框架就不需要你在重新写一遍这所有的逻辑了,简单两步搞定新功能
View Code

调用函数的引用urls.py文件:

from views import login, auth, favicon, index, timer

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

]
View Code

应用代码程序的逻辑部分views.py:

import datetime
import webauth
from urllib.parse import parse_qs


def login(environ):
    with open('./templates/web(1).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)
        print('拆解后的数据', re_data)  # 拆解后的数据 {b'password': [b'123'], b'username': [b'chao']}
        # post请求的返回数据我就不写啦
        pass
    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
View Code

用户名的登录验证webauth.py:

# 对用户名和密码进行验证
def auth(username, password):
    import pymysql
    conn = pymysql.connect(
        host='127.0.0.1',
        port=3306,
        user='root',
        password='1234',
        database='db1',
        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
View Code

静态文件(templates)的index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--看一下百度的登陆-->
<a href="http://127.0.0.1:8080/login">请登录</a>

</body>
</html>
View Code

静态文件(templates)的web(1).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:8080/auth/" method="post">-->
<form action="http://127.0.0.1:8080/auth/" method="get">
    用户名<input type="text" name="username">
    密码 <input type="password" name="password">
    <input type="submit">
</form>

<script>

</script>
</body>
</html>
View Code

静态文件(templates)的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>
View Code

其他文件:图片(wechat.ico)

 

posted @ 2019-05-15 16:04  Amorphous  阅读(622)  评论(0编辑  收藏  举报