flask(一)配置和路由

Flask是一个Python编写的Web轻量级框架。

它和Django的联系以及区别:django是一个大而全的web框架,它内置许多模块,flask是一个小而精的轻量级框架只包含基本的配置; Django有模板,表单,路由,基本的数据库管理等等内建功能。Flask只是一个内核,默认依赖于2个外部库: Jinja2 模板引擎和 WSGI工具集–Werkzeug , flask的使用特点是基本所有的工具使用都依赖于导入的形式去扩展,flask只保留了web开发的核心功能。

常用扩展包:

Flask-SQLalchemy:操作数据库;
Flask-script:插入脚本;
Flask-migrate:管理迁移数据库;
Flask-Session:Session存储方式指定;
Flask-WTF:表单;
Flask-Mail:邮件;
Flask-Bable:提供国际化和本地化支持,翻译;
Flask-Login:认证用户状态;
Flask-OpenID:认证;
Flask-RESTful:开发REST API的工具;
Flask-Bootstrap:集成前端Twitter Bootstrap框架;
Flask-Moment:本地化日期和时间;
Flask-Admin:简单而可扩展的管理接口的框架

一、虚拟环境

虚拟环境是隔离的Python解释器环境。通过创建虚拟环境,可以拥有一个独立的Python解释器环境,相当于对全局的python解释器环境拷贝一份私有的副本, 这样做的好处是可以为每一个项目创建独立的Python解释器环境,因为不同的项目常常会依赖不同版本的库或Python版本。使用虚拟环境可以保持全局Python解释器环境的干净,避免包和版本的混乱,并且可以方便地区分和记录每个项目的依赖,所谓环境追根溯源也是文件,既然是文件就支持拷贝到各个平台上,所以同时提高了可移植性,以便在新环境下复现依赖环境。

1.创建虚拟环境,virtualenv虚拟开发环境

pip install virtualenv
pip install virtualenvwrapper-win

2.利用安装好的模块创建一个虚拟环境mkvirtualenv first_env
创建的路径C:\*\Local\pypa\virtualenv
3.虚拟环境其他相关命令:切换到指定的虚拟环境:workon workon first_env
退出虚拟环境deactivate
删除指定的虚拟环境rmvirtaulenv first_env
列出所有虚拟环境:lsvirtualenv
进入到虚拟环境所在的目录:cdvirtualenv
在虚拟环境中安装Flask模块pip install flask
4.打开pycharm选择已经存在的虚拟环境C:\*\Envs\first_env\Scripts\python.exe

或直接新建flask项目,选择Virtualenv,配置python解释器后新建,在teminal终端上安装pip install flask

二、项目目录详解:
static文件夹 用于存放各种静态文件 css、js、图片等
templates文件夹 用于存放html模板文件
app.py 为主文件 启动项目需要启动该文件
app.py 文件的名字可以自由命名

初始app.py
The flask object implements a WSGI application and acts as the central object.

from flask import Flask
app = Flask(__name__) # __name__参数:Python会根据所处的模块来赋予__name__变量相应的值,此时值为app
@app.route('/') # 用来匹配url,以装饰器实现,装饰器引用的是上面实例化核心类出来的对象。
def hello_world(): # 路由下面跟的函数是视图函数,如果匹配到了路由就会触发视图函数执行,并且return回具体的数据。
	return 'Hello World!'
if __name__ == '__main__':
	app.run(debug=True) # app.run()实现了flask程序在开发环境下运行起来,并且默认ip和端口是127.0.0.1:5000 host,port参数可以设定

导入Flask的核心类实例化对象app,然后app作为装饰器使用匹配url分发给下面的视图函数,然后执行该页面会触发app调用run()方法运行起来整个项目。此时为b/s型。

DEBUG模式
app参数设置 debug=True开发阶段对代码进行修改时使用,flask默认部署后再修改代码,刷新页面不起作用。flask代码中如果出现了异常,浏览器中不会提示具体的错误信息,开启debug模式后会把具体的错误信息发送到浏览器上。flask代码如果被修改了,必须要重启项目修改的代码才会有效,开启debug模式后修改代码后只要ctrl+s项目就会自动重新加载,不需要手动加载整个网站。

对这些配置操作手动解耦,创建settings文件

ENV = 'development'
DEBUG = True

此时app文件改为

from flask import Flask, Response
import settings
app = Flask(__name__)
app.config.from_object(settings) # 配置文件解耦
# app.config.from_pyfile('settings') # 或这个
@app.route('/')
def hello_world():
	return 'Hello World!' # 底层将其送入Response进行封装

@app.route('/han/')
def hello_world():
    return Response('你好啊')
if __name__ == '__main__':
	app.run()

运行python app.py
用http://localhost:5000/或http://127.0.0.1:5000/访问,url是统一资源定位符
默认只能是本机访问,如果需要通过本机ip地址访问,则将host改为‘0.0.0.0’查看本机ip:cmd–ipconfig 查找ipv4地址

针对sever端写东西:

b/s:浏览器/服务器 c/s:客户机/服务器

CS = Client - Server = 客户端- 服务器。
例子: QQ,迅雷,快播,暴风影音,各种网络游戏等等。
BS = Browser - Server = 浏览器 - 服务器。
例子:所有的网站都是BS结构。( 知乎 / 果壳 / 微博 / 等等等等等等 )

区别:
1、开发维护成本
cs开发维护成本高于bs。因为采用cs结构时,对于不同的客户端要开发不同的程序,而且软件安装调试和升级都需要在所有客户机上进行。
bs只需要将服务器上的软件版本升级,然后重新登录就可以了。
2、客户端负载
cs客户端负载大。cs客户端不仅负责和用户的交互,收集用户信息,而且还需要通过网络向服务器发出请求。
bs把事务处理逻辑部分交给了服务器,客户端只是负责显示。
3、安全性
cs安全性高。cs适用于专人使用的系统,可以通过严格的管理派发软件。
bs使用人数多,不固定,安全性低。
4、作用范围
Client/Server是建立在局域网的基础上的。Browser/Server是建立在广域网的基础上的。

三、Werkzeug工具包简介

WSGI:Web服务器网关接口(Python Web Server Gateway Interface,缩写为WSGI)是为Python语言定义的Web服务器和Web应用程序或框架之间的一种简单而通用的接口。Werkzeug是一个WSGI工具包,可以作为一个Web框架的底层库,封装了很多 Web 框架的东西,例如 Request,Response 等 。但它不是一个web服务器,也不是一个web框架。

四、url和路由
一个URL由以下几部分组成,URL建立了与Python视图函数的映射关系:
scheme:代表的是访问的协议,一般为http或者https及ftp等。host:主机名,域名。port:端口号。当你访问一个网站的时候,浏览器默认使用80端口,flask:5000。path:路径 /*。query-string:查询字符串

浏览器地址栏输入的东西url–服务器在app中找路由–执行路由匹配的函数–return–response–到客户端的浏览器

Flask程序中使用路由称之为注册路由,使用的是程序实例提供的app.route()装饰器注册路由,而括号内的字符串就是url,注册路由的过程就是完成了 url和python类或函数映射的过程,这样我们以url访问flask就可以找到对应的程序。所有路由搜索规则都是自上而下匹配
1.默认路由@app.route('/') @app.route('/student_list/')
2.动态路由传参:想根据学生的id找到具体的学生eg:http://127.0.0.1:5000/student_list/8/

@app.route('/student_list//') # 路由绑定,无type:则表示为str
# @app.route('/student_list//') # url必须传int
# 如果app.route中有最后的/而url中没有,则浏览器做了一次重定向
def student_list(student_id):
    return '学生{}号的信息'.format(student_id) # 此时显示url的学生id

def student_list(student_id):
    return '学生{}号的信息'.format(student_id) # 此时显示url的学生id
app.add_url_rule('/student_list//',view_func=student_list) # 路由绑定

any:

@app.route('///') 
# 第一个为class或student都可以 http://127.0.0.1:5000/class/3/
def item(url_path, id):
    if url_path == 'student':
        return '学生{}详情'.format(id)
    else:
        return '班级{}详情'.format(id)

type:

string: 默认的数据类型,接收没有任何斜杠"/"的字符串
int: 整型
float: 浮点型
path:和string类型相似,但是接受斜杠,如:可以接受参数/aa/bb/cc/多条放在一起
uuid: 只接受uuid格式的字符串

五、查询字符串传参
如果浏览器中输入*/s?wd=python&ad=flask,key=value是查询字符串,多个key=value用&相连,将查询字符串作为参数去请求flask程序,这便是查询字符串传参。http://127.0.0.1:5000/student_name/?name=%27zz%27&age=19

@app.route('/student_name/')
def school_name_list():
    name = request.args.get('name')
    age = request.args.get('age')
    return "学生的姓名为{},年龄为{}".format(name, age)

六、url_for()的使用

路径反向解析,若在视图函数中想使用一个url给前端返回,或者在这个视图函数中返回一个模板文件都会使用到url。url_for()利用视图函数名字一般不会改变的特性,利用视图函数的名字去动态精准的获取url,便于开发使用。

url_for('视图函数名字')   # 输出该视图函数url

eg:此时直接访问http://127.0.0.1:5000/,输出/book_list/,网页返回/book_list/

@app.route('/')
def demo1():
    print(url_for("book"))  # 引用的是视图函数的名字 字符串格式
    return url_for("book")
@app.route('/book_list/')
def book():
    return 'flask_book'

url_for处理动态的视图函数
如果想获取动态路由,必须以关键字实参的形式为动态的path部分赋值

@app.route('/test/')
def demo2():
    student_url = url_for('student', id=5)  # id 就是动态path的id 必须赋值
    print(student_url) # 输出/student/5/
    return student_url
@app.route('/student//')
def student(id):
    return 'student {}'.format(id)

url_for为url添加查询字符串
想在路径后面拼出来查询字符串,以关键字实参的形式放到url_for()里面作为参数,会自动拼成路径

@app.route('/test/')
def test():
    school_url = url_for('school', school_level='high', name='college') # 具体要拼接的查询参数 以关键字实参的形式写在url_for里
    print(school_url) # /school/?school_level=high&name=college
    return school_url
@app.route('/school/')
def school():
    return 'school message'

自定义动态路由过滤器
可以通过继承werkzeug.routing 的BaseConverter类从而自定义一个动态路由过滤器的规则

from werkzeug.routing import BaseConverter
class TelephoneConverter(BaseConverter):
    regex = '1[3857]\d{9}' # 第二位为3857中的一个,后面在匹配9个数
app.url_map.converters['tel'] = TelephoneConverter # 添加规则
@app.route('/student//') # 匹配tel规则
def student_detail(telenum):
    return '学生的手机号码是{}'.format(telenum)

七、endpoint参数
写在注册路由的装饰器中的一个参数,学名叫端点,可以理解为函数的别名。如url_for(‘函数名’),现在可以指定endpoint='click'参数来进行翻转url。如果不指定endpoint,默认以函数名作为端点名。

@app.route('/')
def demo1():
    print(url_for("click"))  # 引用的是视图函数的名字 字符串格式
    return url_for("click")
@app.route('/book_list/',endpoint='click')
def book():
    return 'flask_book'

声明变量

{# 声明变量,全局 #}
{% set username='zz' %}
{{ username }}
{# 声明变量,只可在块内使用,局部 #}
{% with num=100 %}
{{ num }}
{% endwith %}

八、蓝图
蓝图的基本使用,flask中可以利用蓝图对程序目录的划分。具体来说可以管理路由划分。如果有很多个视图函数,就应该抽取出来专门的py文件进行管理
flask(一)配置和路由_第1张图片
此时app.py只是负责启动程序settings负责配置

/app
from apps import create_app
app = create_app() # 程序启动的入口,在apps包里的init文件中
if __name__ == '__main__':
    app.run()

/settings
ENV = 'development'
DEBUG = True

base文件是html文件的模板

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} 用户中心{% endblock %}</title>
    <style>
        #head {
            height: 50px;
            background-color: bisque;
        }

        #head ul {
            list-style: none;
            height: 50px;
        }

        #head ul li {
            float: left;
            width: 100px;
            text-align: center;
            font-size: 18px;
            height: 50px;
            line-height: 50px;
        }

        #middle {
            height: 900px;
            background-color: azure;
        }

        #foot {
            height: 50px;
            line-height: 50px;
            background-color: darkseagreen;
        }
    </style>
    {% block mycss %}{% endblock %}
</head>
<body>
    <div id="head">
        <ul>
            <li><a href="">首页</a></li>
            <li><a href="">超市</a></li>
            <li><a href="">会员</a></li>
        </ul>
    </div>
    <div id="middle">
        {% block middle %}
            middle
        {% endblock %}
    </div>
    <div id="foot">foot</div>
    {% block myjs %}{% endblock %}
</body>
</html>

注册界面

{% extends 'base.html' %}

{% block title %}
    用户注册
{% endblock %}

{% block middle %}
    <p style="color: red">{{ msg }}p>
    {# 加url_prefix参数的 post action #}
    {# <form action="/user/register" method="post"> #}
    <form action="{{ url_for('user.register') }}" method="post">
        <p><input type="text" name="username" placeholder="用户名">p>
        <p><input type="password" name="password" placeholder="密码">p>
        <p><input type="password" name="repassword" placeholder="确认密码">p>
        <p><input type="number" name="phone" placeholder="手机号码">p>
        <p><input type="submit" value="用户注册">p>
    form>
{% endblock %}

展示界面

{% extends 'base.html' %}
{% block middle %}
    <h1>用户信息h1>
    <span>当前用户人数是:{{ users |length }} 人span>
    <table border="1" cellspacing="0" width="60%">
        {% for user in users %}
            <tr>
                <td>{{ loop.index }}td>
                <td>{{ user.username }}td>
                <td>{{ user.password }}td>
                <td>{{ user.phone }}td>
                <td><a href="javascript:;" onclick="del('{{ user.username }}')">删除a>td>
            tr>
        {% endfor %}

    table>
{% endblock %}

{% block myjs %}
    <script>
        function del(username){
            // console.log(username)
            // location 地址栏对象
            // 发送一条url
            // alert('{{ url_for('user.register') }}');
            location.href = '{{ url_for('user.del_user') }}'+'?username='+username
        }
    script>
{% endblock %}

apps目录下的init文件负责创建所需对象

from flask import Flask
import settings
from apps.user.view import user_bp

# 为app设置配置文件,此时使用蓝图分发路径
def create_app():
    app = Flask(__name__,template_folder='../templates',static_folder='../static')
    # app是一个核心对象,设置模板文件夹以及静态文件夹,路径为apps的上级目录hello_flask的的子目录
    app.config.from_object(settings)  # 加载配置
    # 注册蓝图对象 需要手动注册蓝图,才会建立上url和视图函数的映射关系
    app.register_blueprint(user_bp)
    # http://127.0.0.1:5000/user/logout 不可访问
    # http://127.0.0.1:5000/logout 可访问

    # app.register_blueprint(user_bp,url_prefix='/user') # 给url加前缀/user
    # http://127.0.0.1:5000/user/logout 可以访问
    # http://127.0.0.1:5000/logout 不可访问
    # print(app.url_map)
    return app

user目录下的view文件负责编写函数以及路径

from flask import Blueprint, request, render_template, redirect, url_for
from apps.user.model import User

# 创建蓝图
user_bp = Blueprint('user', __name__)

# 列表保存的是用户对象
users = []

# 利用蓝图分发路径
@user_bp.route('/')
def user_center():
    return render_template('user/show.html', users=users) # 由于模板文件夹为template

@user_bp.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        # 获取post提交的数据
        username = request.form.get('username')
        password = request.form.get('password')
        phone = request.form.get('phone')
        repassword = request.form.get('repassword')
        if password == repassword:
            for user in users:
                if user.username == username:
                    return render_template('user/register.html', msg='用户名已存在')
            # 创建user对象
            user = User(username, password, phone)
            # 添加到用户列表
            users.append(user)
            # 不加参数的
            # return redirect('/')
            # 加url_prefix参数的
            # return redirect('/user/')
            # 均可
            return redirect(url_for('user.user_center'))
    return render_template('user/register.html')


@user_bp.route('/del')
def del_user():
    # 获取传递的username
    username = request.args.get('username')
    # 根据username找到列表中的user对象
    for user in users:
        if user.username == username:
            # 删除user
            users.remove(user)
            return redirect(url_for('user.user_center'))
    else:
        return '删除失败'

@user_bp.route('/logout', methods=['GET', 'POST'])
def logout():
    return '用户退出'

model文件负责连接数据库等操作

class User:
    def __init__(self, username, password, phone=None):
        self.username = username
        self.password = password
        self.phone = phone

    def __str__(self):
        return self.username

你可能感兴趣的:(flask,python)