美文网首页
flask之改框架

flask之改框架

作者: 马梦里 | 来源:发表于2017-12-13 16:22 被阅读0次

二、修改以前的框架

1. server.py

import socket
import _thread

from request import Request
from utils import log

from routes import error

from routes.routes_todo import route_dict as todo_routes
from routes.api_todo import route_dict as todo_api
from routes.routes_weibo import route_dict as weibo_routes
from routes.routes_user import route_dict as user_routes
from routes.routes_static import route_dict as static_routes

def response_for_path(request):
    r = {}
    r.update(todo_api())
    r.update(todo_routes())
    r.update(weibo_routes())
    r.update(user_routes())
    r.update(static_routes())
    response = r.get(request.path, error)
    return response(request)

def process_request(connection):
    r = connection.recv(1024)
    r = r.decode()
    # 把原始请求数据传给 Request 对象
    request = Request(r)
    # 用 response_for_path 函数来得到 path 对应的响应内容
    response = response_for_path(request)
    if 'static' in request.path:
        log("response for static size: {}".format(len(response)))
    else:
        log("response log:\n{}".format(response.decode()))
    connection.sendall(response)
    connection.close()

def run(host, port):
    # 初始化 socket 套路
    # 使用 with 可以保证程序中断的时候正确关闭 socket 释放占用的端口
    log('开始运行于', '{}:{}'.format(host, port))
    with socket.socket() as s:
        # 使用 下面这句 可以保证程序重启后使用原有端口, 原因忽略
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        s.bind((host, port))
        s.listen(5)
        while True:
            connection, address = s.accept()
            # 第二个参数类型必须是 tuple
            _thread.start_new_thread(process_request, (connection,))

if __name__ == '__main__':
    config = dict(
        host='127.0.0.1',
        port=3000,
    )
    run(**config)

改为:

from flask import(
    Flask,
)
from routes.routes_user import user_view
from routes.routes_static import static_view

if __name__ == '__main__':
    app = Flask(__name__)
    app.register_blueprint(user_view)
    app.register_blueprint(static_view)
    config = dict(
        debug = True,
        host='127.0.0.1',
        port=8000,
    )
    app.run(**config)

run函数已经封装好了,路由由Blueprint处理。这个脚本就两个功能,启动服务器和分发路由。
知识点:

  • Blueprint 的使用,记住就好。

2.主页视图

from routes import current_user, login_required
from routes import http_response
from utils import template, log

def route_index(request):
    u = current_user(request)
    log('current user', u)
    body = template('index.html', username=u.username)
    return http_response(body)

def route_static(request):
    filename = request.query.get('file', )
    path = 'static/' + filename
    with open(path, 'rb') as f:
        header = b'HTTP/1.1 200 OK\r\n\r\n'
        binary = header + f.read()
        return binary

def route_dict():
    r = {
        '/': login_required(route_index),
        '/static': login_required(route_static),
    }
    return r

改为:

from flask import (Blueprint,render_template,send_from_directory,request,)
from routes import current_user, login_required
from utils import log

static_view = Blueprint('static_view', __name__)

# 先处理路由函数,如果没注册,再重定向到登录界面
@static_view.route('/')
@login_required
def route_index():
    u = current_user()
    return render_template('index.html', username=u.username)

@static_view.route('/static')
def route_static():
    filename = request.args.get('file', None)
    return send_from_directory('static/' , filename)

知识点:

  • 权限函数在路由函数之下,原因是先找到路由,发现没登录,再执行权限函数
  • Blueprint 的使用
    -flask.send_from_directory(dictionary, filename)
    就是读取文件,两个参数,一个是路径,一个是文件名;
    current_user()函数也需要更改
def current_user(request):
    session_id = request.cookies.get('sid', '')
    sessions = Session.all()
    for s in sessions:
        if s.session_id == session_id:
            u = User.find_by(id=s.user_id)
            return u
    return None

# 改为:去掉request参数,在脚本调用flask.request,
# cookies也是通过POST进行传递的,在body里面;

def current_user():
    session_id = request.cookies.get('sid', '')
    sessions = Session.all()
    for s in sessions:
        if s.session_id == session_id:
            u = User.find_by(id=s.user_id)
            return u
    return None

3.登录和注册视图:

from models.session import Session
from routes import (random_str,redirect,http_response)
from utils import log
from utils import template
from models.user import User

def route_login(request):
    log('login, cookies', request.cookies)
    if request.method == 'POST':
        form = request.form()
        u = User(form)
        if u.validate_login():
            session_id = random_str()
            u = User.find_by(username=u.username)
            s = Session.new(dict(
                session_id=session_id,
                user_id=u.id,
            ))
            log('session', s)
            headers = {
                'Set-Cookie': 'sid={}'.format(session_id)
            }
            # 登录后定向到 /
            return redirect('/', headers)
    # 显示登录页面
    body = template('login.html')
    return http_response(body)

def route_register(request):
    if request.method == 'POST':
        form = request.form()
        u = User.new(form)
        if u.validate_register():
            # 注册成功再保存
            u.save()
            # 注册成功后 定向到登录页面
            return redirect('/login')
        else:
            # 注册失败 定向到注册页面
            return redirect('/register')
    # 显示注册页面
    body = template('register.html')
    return http_response(body)

def route_dict():
    r = {
        '/login': route_login,
        '/register': route_register,
    }
    return r

改为:

from models.session import Session
from flask import (Blueprint,render_template,redirect,request,make_response,)
from routes import random_str
from utils import log
from models.user import User

user_view = Blueprint('user_view', __name__)

@user_view.route('/login', methods = ['POST', 'GET'])
def route_login():
    log('login, cookies', request.cookies)
    if request.method == 'POST':
        form = request.form
        u = User(form)
        if u.validate_login():
            session_id = random_str()
            u = User.find_by(username=u.username)
            s = Session.new(dict(
                session_id=session_id,
                user_id=u.id,
            ))
            log('session', s)
            # 登录后定向到 /
            redirect_to_index = redirect('/')
            response = make_response(redirect_to_index)
            response.set_cookie('sid', value=session_id)
            return response
    # 显示登录页面
    return render_template('login.html')

@user_view.route('/register', methods = ['POST', 'GET'])
def route_register():
    if request.method == 'POST':
        form = request.form
        u = User.new(form)
        if u.validate_register():
            # 注册成功再保存
            u.save()
            # 注册成功后 定向到登录页面
            return redirect('/login')
        else:
            # 注册失败 定向到注册页面
            return redirect('/register')
    # 显示注册页面
    return render_template('register.html')
  1. request为全局变量,form为属性。template改为render_template()
  2. 主要是cookies设置的改变
redirect_to_index = redirect('/')
    response = make_response(redirect_to_index)
    response.set_cookie('sid', value=session_id)
    return response

做出了两个响应,一个是重定向到index页面,一个是响应一个cookies
在登录成功之后,不仅要返回重定向,还要返回cookies

  1. 但是返回重定向为什么要用make_response()呢?
    因为return的内容,浏览器会默认为body,而cookies储存在header中。但是我们没有办法更改响应结构,就只能去创建一个请求结构了。构造一个response需要基于某种情况,这种是重定向,还可以是渲染页面(response = make_response(render_template('','')))。
  2. cookies的再理解:
    cookiescookies是保存在客户端的,当用户发送登录信息给服务器的时候,服务器将用户名存在请求头发送给浏览器,这样,浏览器以后的请求中都包含了用户名这个字段,服务器就可以通过这个字段辨别用户了。
    sessionssessions是保存在服务器的,在服务器端生成的,是依赖于cookies的,只不过在cookies的外面套上了一件衣服,将重要信息掩盖。客户将登陆信息发送给服务器,服务器生成一个随机字符串赋值于session_id,构架一个session_id和用户名两个字段的字典,一一对应,并将session_id发送给客户端。这样服务器就可以通过客户端发过来的session_id来辨别用户了。
    客户端每次登陆,都会生成一个随机字符串,服务器和客户端通过这个进行识别。下次相同用户登陆的时候,又会生成其他随机字符串。
login_required也需要修改:
def login_required(route_function):
    """
    def f(request):
        u = current_user(request)
        if u is None:
            return redirect('/login')
        else:
            return route_function(request)
    return f

改为:

def login_required(route_function):
    def f():
        u = current_user()
        if u is None:
            return redirect('/login')
        else:
            return route_function()
    return f

4.todo首页视图

from models.todo import Todo
from routes import (
    redirect,
    http_response,
    current_user,
    login_required,
)
from utils import template, log

def index(request):
    u = current_user(request)
    body = template('todo_index.html')
    return http_response(body)

def route_dict():
    d = {
        '/todo/index': login_required(index),
    }
    return d

改为:

from flask import (render_template, Blueprint,)
from routes import login_required
todo_view = Blueprint('todo_vies', __name__)
@todo_view.route('/todo/index')
@login_required
def index():
    return render_template('todo_index.html')

5.api_todo

from routes import json_response
from models.todo import Todo

# 本文件只返回 json 格式的数据
# 而不是 html 格式的数据
def all(request):
    todos = Todo.all_json()
    return json_response(todos)

def add(request):
    # 得到浏览器发送的表单, 浏览器用 ajax 发送 json 格式的数据过来
    # 所以这里我们用新增加的 json 函数来获取格式化后的 json 数据
    form = request.json()
    # 创建一个 todo
    t = Todo.new(form)
    # 把创建好的 todo 返回给浏览器
    return json_response(t.json())

def delete(request):
    todo_id = int(request.query.get('id'))
    t = Todo.delete(todo_id)
    return json_response(t.json())

def update(request):
    form = request.json()
    log('api todo update', form)
    todo_id = int(form.get('id'))
    t = Todo.update(todo_id, form)
    return json_response(t.json())

def route_dict():
    d = {
        '/api/todo/all': all,
        '/api/todo/add': add,
        '/api/todo/delete': delete,
        '/api/todo/update': update,
    }
    return d

改为

from flask import (request, Blueprint, jsonify)
from routes import login_required
from utils import log
from models.todo import Todo

api_todo_view = Blueprint('api_todo_view', __name__)

# 本文件只返回 json 格式的数据
# 而不是 html 格式的数据
@api_todo_view.route('/api/todo/all')
@login_required
def api_all():
    todos = Todo.all_json()
    return jsonify(todos)

@api_todo_view.route('/api/todo/add', methods = ['POST'])
@login_required
def api_add():
    # 得到浏览器发送的表单, 浏览器用 ajax 发送 json 格式的数据过来
    # 所以这里我们用新增加的 json 函数来获取格式化后的 json 数据
    form = request.json
    # 创建一个 todo
    t = Todo.new(form)
    # 把创建好的 todo 返回给浏览器
    return jsonify(t.json())

@api_todo_view.route('/api/todo/delete')
@login_required
def api_delete():
    todo_id = int(request.args.get('id', None))
    t = Todo.delete(todo_id)
    return jsonify(t.json())

@api_todo_view.route('/api/todo/update', methods = ['POST'])
@login_required
def api_update():
    form = request.json
    log('api todo update', form)
    todo_id = int(form.get('id'))
    t = Todo.update(todo_id, form)
    return jsonify(t.json())

login_required()函数:

from functools import wraps
def login_required(route_function):
    @wraps(route_function)
    def f():
        u = current_user()
        if u is None:
            log('非登录用户')
            return redirect('/login')
        else:
            return route_function()

    return f
  1. 自己写的weibo程序
# 用于评论的更新:评论的user_id与登录的id一直
def comment_same_user_required(route_function):
    @wraps(route_function)
    def f():
        u = current_user()
        if request.method == 'GET':
            comment_id = int(request.args.get('id', None))
        else:
            form = request.json
            comment_id = form.get('id', None)
        c = Comment.find(int(comment_id))
        if u.id == c.user_id:
            log('权限用户')
            return route_function()
        else:
            return redirect('/webo/index')
    return f

这里注意一点,由于ajax发过来的数据是json格式,所以form数据需要通过request.json来接收,二GET请求发过来的数据在url里面,不是json格式,所以可以直接取。ajax(method,path,form,callback)

三个知识点:

  1. request.json
  2. jsonify()
  3. from functools import wraps @wraps(参数为母函数参数)
    http://www.w3school.com.cn/json/
    http://blog.csdn.net/hqzxsc2006/article/details/50337865
    https://www.tuicool.com/articles/NzEbqmj

【13-2(全)】

相关文章

  • flask之改框架

    二、修改以前的框架 1. server.py 改为: run函数已经封装好了,路由由Blueprint处理。这个脚...

  • Flask

    Flask Introduction PythonWEB框架之Flask Flask Back-end Manag...

  • Flask框架——Sijax

    上篇文章我们学习了Flask框架——Flask-SQLite数据库,这篇文章我们学习Flask框架——Flask-...

  • python flask安装和命令

    Flask Web开发实战学习笔记 Flask简介 Flask是使用Python编写的Web微框架。Web框架可以...

  • flask框架入门级基础

    摘要 flask框架是一个微框架,即:微框架中的“微”意味着 Flask 旨在保持核心简单而易于扩展。Flask ...

  • Flask框架——flask-caching缓存

    上篇文章我们学习了Flask框架——Session与Cookie,这篇文章我们来学习Flask框架——flask-...

  • flask入门

    Flask入门 Flask入门WEB工作原理Flask框架flask_script扩展蓝本(blueprint) ...

  • flask快速入门

    Flask简介 Flask框架是一个基于python的微型的web框架.微,并不是说Flask功能比较弱,微框架的...

  • Django框架——迁移

    一、横向对比 Django框架:自带orm Flask框架:flask-sqlalchemy, 先从sqlalch...

  • FLASK第一部分

    内容,Flask框架 1、介绍Flask,Django,Tornado 框架 Django:重量级web框...

网友评论

      本文标题:flask之改框架

      本文链接:https://www.haomeiwen.com/subject/jeczixtx.html