python Django之Web框架本质 (2)

文章目录

  • 一.Web应用本质
    • 1.socket本质
  • 二.发送HTTP协议、响应
    • 1.HTTP协议
    • 2.HTTP发送响应
      • ◼ 静态网页
      • ◼ 动态网页
  • 三.jinja2模板渲染

一.Web应用本质

为了了解Django的客户端与服务端的交互原理,我们需要了解Web应用的本质方便以后更加的理解Django原理

在Web应用中,服务器把网页传给浏览器,实际上就是把网页的HTML代码发送给浏览器,让浏览器显示出来。而浏览器和服务器之间的传输协议是HTTP。所以本质上就是:

  • 浏览器发送一个HTTP请求
  • 服务器收到请求,生成一个HTML文档
  • 服务器把HTML文档作为HTTP响应的Body发送给浏览器
  • 浏览器收到HTTP响应,从HTTP Body取出HTML文档并显示。

而在http协议中,我们可以用socket来实现

1.socket本质

web服务器本质上可以认为是一段代码,可以不断的处理http协议的网络请求,而http协议可以使用socket实现,并且http协议是一个无状态的协议,即浏览器发起请求,服务器接收请求,然后给浏览器回复数据,然后断开连接;那么可以用socket来实现一个最简单的web服务器。

  • HTTP:
    无状态、短连接
  • TCP:
    不断开(socket连接)
  • 服务器把HTML文档作为HTTP响应的Body发送给浏览器
  • WEB应用(网站)
    • 浏览器(socket客服端)
      在客户端访问网址后,通过ping 网址 转化为ip地址进行访问(默认监听80端口)
    • 浏览器(socket服务端)
      1. 监听ip和端口
      2. 收到客户端传来的数据
      3. 响应客户端,发送响应数据
      4. 断开客户端连接

示意如下:

import socket
sock = socket.socket()
# 网页和监听端口(这里先默认本机端口的8080)
sock.bind(('127.0.0.1',8080))
# 等待五个用户
sock.listen(5)
# 因为socket是TCP协议不断开
while True:
	#等待
	conn,addr= sock.accept()
	# 有人来连接
	# 获取用户发送的数据
	data = conn.recv(8096)
	# 回数据,转字节
	conn.send(b'123123')
	# 断开客户端连接
	conn.close()

访问127.0.0.1:8080

示意如下:
python Django之Web框架本质 (2)_第1张图片


二.发送HTTP协议、响应


1.HTTP协议

在html中发送获取数据都遵从着HTTP协议,随着时间的变化一点一点的在改变,直到现在,我们可以通过socket发来的请求打印data来查看http发送的响应数据:

print(data)
#返回
"""
响应头
状态:200 OK
'GET /(get请求数据默认放这) HTTP/1.1' \
'Host: 127.0.0.1:8080' \
'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0' \
'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' \
'Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2' \
'Accept-Encoding: gzip, deflate' \
'Connection: keep-alive' \
'Upgrade-Insecure-Requests: 1'

请求体:如果是post请求数据放这

响应体
'GET /favicon.ico HTTP/1.1' \
'Host: 127.0.0.1:8080' \
'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0' \
'Accept: image/webp,*/*' \
'Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2' \
'Accept-Encoding: gzip, deflate' \
'Connection: keep-alive' \
'Referer: http://127.0.0.1:8080/'


"""

很显然我们上面写的代码没有根据HTTP的协议发送请求,应该遵循HTTP协议,用户在页面上看到的内容”字符串“(看到页面效果,是由浏览器解析出来的)

示意如下:

import socket
sock = socket.socket()
# 网页和监听端口(这里先默认本机端口的8080)
sock.bind(('127.0.0.1',8080))
# 等待五个用户
sock.listen(5)
# 因为socket是TCP协议不断开
while True:
	#等待
	conn,addr= sock.accept()
	# 有人来连接
	#1. 获取用户发送的数据
	data = conn.recv(8096)
    
    # 4. 遵循http协议
	conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
	# 5. 返回数据,转字节
	conn.send(b'123123')
	# 6. 断开客户端连接
	conn.close()
   



2.HTTP发送响应

但是我们目前怎么样都只有一个页面,不能像其他的网站一样有多个页面,所以我们要从客户端发来的请求中拿到数据在做出响应在返回:

  1. 获取用户发送的数据
  2. 接收请求传来的数据
  3. 分割数据
  4. 遵循http协议
  5. 返回相应数据,转字节
  6. 断开客户端连接

示意如下:

import socket

# 相应数据函数
def f1(request):
    return b"f1"


def f2(request):
    return b"f2"

# 类似django的路由
routers = [
    ('/xxx', f1),
    ('/ooo', f2),
]

# 主函数
def run():
    sock = socket.socket()
    # 网页和监听端口(这里先默认本机端口的8080)
    sock.bind(('127.0.0.1', 8080))
    # 等待五个用户
    sock.listen(5)
    # 因为socket是TCP协议不断开
    while True:
        # 等待
        conn, addr = sock.accept()
        # 有人来连接
        # 1. 获取用户发送的数据
        data = conn.recv(8096)
        # 2. 接收请求传来的数据
        data = str(data, encoding='utf-8')
        # 3. 分割数据,请求头,和请求体
        headers, bodys = data.split('\r\n\r\n')
        temp_list = headers.split('\r\n')
        # 获取一.get请求 二.访问url 三.请求体
        res, url, hea = temp_list[0].split(' ')
        func_name = None
        # 4. 遵循http协议
        conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
        # 这时候打印的就是后缀的值
        print(url)
       	# 遍历路由
        for item in routers:
            if item[0] == url:
            	# 判断是否是该url返回函数地址
                func_name = item[1]
                break
        # 判断函数是否存在
        if func_name:
            response = func_name(data)
        else:
            response = b"404 not found"
            
		 # 5. 返回相应数据,转字节
        conn.send(response)
        # 6. 断开客户端连接
        conn.close()


if __name__ == '__main__':
    run()

访问127.0.0.1:8080

示意如下:
python Django之Web框架本质 (2)_第2张图片


所以通过上面例子我们可以写一个html然后渲染。

◼ 静态网页

因为如果想要数据库实时动态产生,我们需要数据库的帮助,不过在开始介绍前,我们先写静态网页,首先在当前主目录下创建两个文件夹动态网页和静态网页。用于区分一下动态网页和静态网页。

在静态文件/index.html中定义视图如下:


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>title>
head>
<body>
        <table border="1">
            <thead>
                <tr>
                    <th>IDth>
                    <th>用户名th>
                    <th>邮箱th>
                tr>
            thead>
            <tbody>
                <tr>
                    <th>1th>
                    <th>rootth>
                    <th>[email protected]th>
                tr>
            tbody>
        table>
body>
html>

在f1中定义函数如下:

def f1(request)
	 f=open('静态网页/index.html', 'rb')
	    data=f.read()
	    f.close()
	    return data

访问127.0.0.1:8080/xxx

示意如下:

python Django之Web框架本质 (2)_第3张图片

◼ 动态网页

在前面的文章有写到操作数据库的方法,种类很多这里我们使用pymysql来实现,如果没看到这里的可以点开链接:点我!!!进行查看。

  1. 导入驱动程序
pip install pymysql
  1. 创建数据库连接
import pymysql
# 创建连接
conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='xxx', db='myemployees')
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
# 关闭
cursor.close()
conn.close()

在这里我们把/ooo改成/userlist.htm为了告诉大家django的路由和这个很像

routers = [
    ('/xxx', f1),
    ('/userlist.htm', f2),
]

在动态网页/userlist.html中定义视图如下:


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>title>
head>
<body>
        <table border="1">
            <thead>
                <tr>
                    <th>IDth>
                    <th>用户名th>
                    <th>邮箱th>
                tr>
            thead>
            <tbody>
                <tr>
                 @@content@@
                tr>
            tbody>
        table>
body>
html>

因为返回的是字符串所以我们可以对字符串进行拼接成html看得懂的,然后在从html转化为字节传给浏览器。

在f2中定义函数如下:

def f2(request):
# 创建连接
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', 		db='myemployees')
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    # 在数据库查询数据
    cursor.execute("SELECT employee_id,first_name,phone_number FROM employees")
    # 获取所有查到的数据
    user_list = cursor.fetchall()
    # 关闭
    cursor.close()
    conn.close()
    # 拼接
    content_list = []
    for row in user_list:
        tp = "%s%s%s" % (row['employee_id'], row['first_name'], row['phone_number'])
        # 添加进来
        content_list.append(tp)
    # 拼接到一起
    content = "".join(content_list)
    # 打开userlist.html
    f = open('动态网页/userlist.html', 'r', encoding='utf-8')
    # 获得字符串(模板的渲染)
    template = f.read()
    # 关闭
    f.close()
    # 把我之前在html写的@@content@@修改
    data = template.replace('@@content@@', content)
    # 把写好的字符串转成字节的形式给浏览器渲染成可视化界面
    return bytes(data, encoding='utf-8')

此时访问127.0.0.1:8080/userlist.htm

示意如下:
python Django之Web框架本质 (2)_第4张图片


三.jinja2模板渲染

对于上面的一系列操作,相对麻烦,又要替换字符串,转字节,还得自己拼接,这时python中就出来了一个模块jinjia2,它可以帮助我们进行模板的渲染,而渲染的规则要和它一致

  1. 安装jinja2模块
pip install jinja2
  1. 添加一个路由和函数
routers = [
    ('/xxx', f1),
    ('/userlist.htm', f2),
    ('/host.html',f3),
]

在动态网页/host.html中定义视图如下:


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>title>
head>
<body>
        <table border="1">
            <thead>
                <tr>
                    <th>IDth>
                    <th>用户名th>
                    <th>邮箱th>
                tr>
            thead>
            <tbody>
                {% for row in user_list %}
                    <tr>
                        <td>{
    { row.employee_id }}td>
                        <td>{
    { row.first_name }}td>
                        <td>{
    { row.phone_number }}td>
                    tr>
                {% endfor %}
            tbody>
        table>
body>
html>

在f3中定义函数如下:

from jinja2 import Template

def f3(request):
    f = open('动态网页/host.html', 'r', encoding='utf-8')
    # 获得字符串(模板的渲染)
    data = f.read()
    # 关闭
    f.close()
    # 创建连接
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='myemployees')
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    # 在数据库查询数据
    cursor.execute("SELECT employee_id,first_name,phone_number FROM employees")
    # 获取所有查到的数据
    user_list = cursor.fetchall()
    # 关闭
    cursor.close()
    conn.close()
    # 使用jinja2渲染
    template=Template(data)
    data=template.render(user_list=user_list)
    # 上传
    return data.encode('utf-8')

此时访问此时访问127.0.0.1:8080/host.html

示意如下:

python Django之Web框架本质 (2)_第5张图片

你可能感兴趣的:(django,django,mysql,html)