Django之web框架

什么是web框架?

  要想知道web框架,就得先了解什么是web服务,web服务就是我们平常上网的过程,我们点击新闻按钮,浏览器就会向服务端发送请求,服务器就会把新闻相关的内容发给浏览器,然后浏览器把内容显示到屏幕上,这一个过程就是web服务。而这种能够支持web服务的结构可以称为web框架。

为何要手动搭建一个web框架?

  主要还是为了能对Django的底层实现原理有个了解,能够更好的使用Django。

前期知识准备:

1、web框架 action 1

  在之前用过基于socket模块的c/s结构,这里我们可以把服务端拿出来改改直接当作浏览器的服务端使用,
 1 import socket
 2 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 3 sock.bind(('127.0.0.1', 8080))
 4 sock.listen()
 5
 6 while True:
 7     conn, addr = sock.accept()
 8     data = conn.recv(8096)
 9     # 下面是http协议规定的响应状态信息,需要加上
10     conn.send(b"HTTP/1.1 200 OK\r\n\r\n")
11     conn.send(b"OK")
12     conn.close()

  1.1 需求:返回一个html

    方法:既然能返回字符串了,那就可以返回一个html文件(本质就是一个字符串)

1 那只要把上面第10、11行改成下面的就行:
2 with open("test.html", "rb") as f:
3     conn.send(b"HTTP/1.1 200 OK\r\n\r\n")
4     conn.send(f.read())

  1.2 需求:返回多个页面

    解决办法:http协议中的请求信息中有网址,可以拿到然后判断用户要访问的网页

 1 while True:
 2     conn, addr = sock.accept()
 3     data = conn.recv(1024)
 4     print(data)
 5     data = data.decode('utf-8')
 6     # 通过请求头信息得到网址
 7     current_path = data.split('\r\n')[0].split(' ')[1]
 8     conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
 9     # 实现多个页面都能访问
10     if current_path == '/index':
11         with open('index.html','rb') as f:
12             conn.send(f.read())
13     elif current_path == '/login':
14         with open('index.html','rb') as f:
15             conn.send(f.read())
16     elif current_path == '/register':
17         with open('register.html','rb') as f:
18             conn.send(f.read())
19     else:
20         conn.send(b'404')
21     conn.close()

  1.3 需求:重构优化代码

    方法:把if里面的内容拿出来单放到一个函数里,然后用一个字典保存网址和函数名的对应关系

import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('127.0.0.1', 8080))
sock.listen()

def index():
    with open('index.html','rb') as f:
        data = conn.send(f.read())
    return data

def login():
    with open('login.html','rb') as f:
        data = conn.send(f.read())
    return data

def regitser():
    with open('register.html','rb') as f:
        data = conn.send(f.read())
    return data

# 定义一个字典,保存函数名和网址的对应关系
func_dic = {
    "/index": index,
    "/login": login,
    "/register": register,
}

while True:
    conn, addr = sock.accept()
    data = conn.recv(1024)
    print(data)
    data = data.decode('utf-8')
    # 通过请求头信息得到网址
    current_path = data.split('\r\n')[0].split(' ')[1]
    # 实现多个页面都能访问
    if current_path in func_dic:
        response = func_dic.get(current_path)()
    else:
        response = b'404'

    conn.send(b'HTTP/1.1 200 OK\r\n\r\n')
    conn.send(response)
    conn.close()

  1.4 需求:动态显示时间

    方法:在html文件设置特殊字符串,然后用时间字符串去替换

// date.html 文件
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
@@time@@  <!--特殊字符串用来替换-->
</body>
</html>
# 加入下面函数
def date():
     ctime = datetime.now().strftime('%Y-%m-%d %X')
    # 打开文件
    with open('date.html','r',encoding='utf-8') as f:
        data = f.read()
    res = data.replace('@@time@@',ctime)
    return res.encode("utf-8")

func_dic = {
    "/index": index,
    "/login": login,
    "/register": register,
    "/date": date,
} 

2、web框架 action 2

  各种需求都满足了,但是不够高大上,没有发挥出python的本质“调包侠”,所以提出需求,不要自己写socket,不要自己替换字符串,去用别人的模块。

  2.1 需求:不要自己写socket

    方法:使用wsgiref模块

import time
from wsgiref.simple_server import make_server

def index():
    with open('index.html','rb') as f:
        data = conn.send(f.read())
    return data

def login():
    with open('login.html','rb') as f:
        data = conn.send(f.read())
    return data

def regitser():
    with open('register.html','rb') as f:
        data = conn.send(f.read())
    return data

# 定义一个字典,保存函数名和网址的对应关系
func_dic = {
    "/index": index,
    "/login": login,
    "/register": register,
}

def run_server(env, response):
    # 设置HTTP响应的状态码和头信息
    # 列表里面放的是请求首行的信息,可以不放,但是必须写
    response('200 OK', [])
    url = env.get('PATH_INFO') # 取到用户输入的url

    # 实现多个页面都能访问
    if url in func_dic:
        res = func_dic.get(url)()
    else:
        res = b'404'
    return [res]

if __name__ == '__main__':
    httpd = make_server('127.0.0.1', 8090, run_server)
    httpd.serve_forever()

  2.2 需求:按功能把文件拆分,不要放到同一个文件里

// 把函数名和网址的对应关系单独放在一个文件urls.py下
//  urls.py
func_dic = {
    "/index": index,
    "/login": login,
    "/register": register,
}

// 把函数单独放在一个文件下
// view.py
def index():
    with open('index.html','rb') as f:
        data = conn.send(f.read())
    return data

def login():
    with open('login.html','rb') as f:
        data = conn.send(f.read())
    return data

def regitser():
    with open('register.html','rb') as f:
        data = conn.send(f.read())
    return data

  2.3 需求:从数据库中获取数据,不用自己替换字符串

    方法:使用pymysql,jinja2模块

/ user.html 文件
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
<body>
<h1>{{ data }}</h1>
<h1>{{ data.name }}</h1>
<h1>{{ data['name'] }}</h1>
<h1>{{ data.get('name') }}</h1>
<h1>{{ data.age }}</h1>
</body>
</html>
// view.py 模块
def get_db_info(env):
    conn = pymysql.connect(
        host = '127.0.0.1',
        port = 3306,
        user = 'root',
        password = '',
        database = 'db1',
        charset = 'utf8',
        autocommit = True
    )
    cursor = conn.cursor(pymysql.cursors.DictCursor)
    cursor.execute('select * from userinfo')
    user_list = cursor.fetchall()
    # 打开文件渲染到前端页面
    with open('user.html','r',encoding='utf-8') as f:
        data = f.read()
    tmp = Template(data)
    res = tmp.render(user_list=user_list)
    return res.encode("utf-8")

  总结:以上就是web框架,也是Django实现的基本方式:请求来了,先到wsgiref模块,然后经过路由模块urls.py分发, 到视图模块view.py执行,从模板文件拿html文件,从数据库拿数据,处理好后,然后经过wsgiref模块返回给浏览器。

3、初识Django

  python 三大主流框架

  安装前的注意事项:

    1. 计算机名称不能是中文,不然启动时会报错

    2. 一个pycharm窗口对应一个项目

    3. 文件路径命名尽量不要用中文

    4. 开启django确保端口不能重复

  3.1 命令行操作django

    1. 安装:pip3 install django

    2. 创建一个项目:django-admin startproject '项目名'

    3. 创建一个app应用:python manage.py startapp "应用名app01"

    4. 注册app01: 在setting.py文件下(只要新创建的app都要添加以下配置

      在列表INSTALLED_APPS下添加'app01.apps.App01Config'

    5. 创建空文件夹templates: mkdir templates

    6. 添加模板文件配置:在setting.py下添加配置

      在字典TEMPLATES下的DIRS添加[os.path.join(BASE_DIR, 'templates')]

    7. 配置静态文件:setting.py 的末尾,添加STATICFILES_DIRS = (os.path.join(BASE_DIR, "static"),)

    8. 启动django python manage.py runserver

  3.2 pycharm 创建django

    1. 安装启动

 

    2. 文件配置

# 模板文件配置:
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, "template")],  # template文件夹位置
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

# 静态文件配置
STATIC_URL = '/static/'  # HTML中使用的静态文件夹前缀
STATICFILES_DIRS = [
    # 依次从下面文件夹查找,如果都没找到,才会报错
    os.path.join(BASE_DIR, "static"),  # 静态文件存放位置
    os.path.join(BASE_DIR, "static1"),
]

# 暂时禁止csrf中间件
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

  3.3 启动Django时报错

      1. Django 启动时报错 UnicodeEncodeError ...

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

      2. Django 启动时报错  SyntaxError: Generator expression must be parenthesized...

        原因:通常是由于解释器与Django之间的兼容问题,建议使用3.6版本的解释器,就不会有该问题了。

  3.4 django程序执行过程

浏览器请求到后
// 1. 经过wsgiref模块
// 2. 然后经过urls.py 下的路由分发,如果不在就报错
    urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^index/', views.index),
]

// 3. 如果在上面,就到view.py函数下执行函数
def index(request):
    return HttpResponse("index")

//4. 把结果返回给浏览器

  3.5 返回函数三件套

// view.py 视图下
from django.shortcuts import HttpResponse, render, redirect

// HttpResponse 返回的是一个字符串
def index(request):
    # 业务逻辑代码
    return HttpResponse("OK")

// render
// 需要request参数外还接受一个待渲染的模板文件和一个保存具体数据的字典参数
// 使用方法类似于janja2
def index(request):
    # 业务逻辑代码
    return render(request, "index.html", {"name": "sun", "hobby": ["run", "泡吧"]})

// rendirect
// 接受一个URL参数,表示跳转到指定的URL,可以是自己的,也可以是别人的

 

posted @ 2019-04-17 08:48  yw_sun  阅读(208)  评论(0)    收藏  举报