flask3
2019-03-07 本文已影响0人
遥远的她197
hello.py文件是主页面,在开发时主页面不要写太多内容,所以我们要优化主页面。
创建一个app包,
image.png
__init__.py文件必须要有,有了这个py文件
才能把app文件当做一个库来使用
然后再创建一个views.py文件用来
存放hello.py文件中的路径文件
此时肯定会有很多的错误,
@app.route('/')不能跨文件,我们
就需要在Terminal下载一个蓝图文件
pip install Blueprint
# 蓝图, 管理路由地址
# 第一步:生成蓝图对象
blue = Blueprint('first', __name__)
然后再hello.py(主页面)
# app.views 此时它是一个库了
导入
from app.views import blue
此时必须把from hello import app删了, app已变成blue,
app不能跨文件,不删就会循环导入会报错
第二步:管理蓝图
app.register_blueprint(blueprint=blue) # 注册一下
再回到views.py文件中
将所有的@app.route()改为
@blue.route()
再导入那些报红的库
views.py文件中
里面的redirect, url_for都是flask自带的, 导出来就行了
from flask import render_template, make_response, \
request, session, Blueprint, redirect, url_for
# from hello import app 没用了 因为app已改成blue, app不能跨py文
# 件, 不删就会循环导入会报错
from utils.functions import is_login
# 蓝图, 管理路由地址
# 第一步: 生成蓝图对象
blue = Blueprint('first', __name__)
@blue.route('/')
def hello():
return 'hello world' # 这就是后端给前端的响应的内容
@blue.route('/make_res/')
def make_res():
# make_response('响应内容', 响应状态码)创建响应对象 响应状态码默认为200
# return make_response('hello flask day02', 200)
# return make_response('<h2>今天天气不好</h2>')
index = render_template('first.index')
return make_response(index, 200)
@blue.route('/register/', methods=['GET', 'POST'])
def register():
print(request.method)
if request.method == 'GET':
return render_template('register.html')
if request.method == 'POST':
# 模拟注册功能
# 1.获取页面中传递的参数
username = request.form.get('username')
password = request.form.get('password')
password2 = request.form.get('password2')
# 模拟注册
if username == 'coco' and password == password2 \
and password == '123456':
# 返回登录页面
return redirect(url_for('first.login')) # 同时跳转地址和页面
# return render_template('login.html') # 跳转页面,但不会修改地址
else:
return render_template('register.html')
@blue.route('/login/', methods=['GET', 'POST'])
def login():
if request.method == 'GET':
return render_template('login.html')
if request.method == 'POST':
# 1.获取参数
print(123)
username = request.form.get('username')
password = request.form.get('password')
# 2.模拟登录
if username == 'coco' and password == '123456':
# 向cookie中设置参数 (钥匙)
print('899')
res = make_response(redirect(url_for('first.index')))
# 设置cookie
res.set_cookie('token', '12345678', max_age=3000)
return res
else:
return render_template('login.html')
@blue.route('/logout/')
def my_logout():
# 注销
res = make_response(render_template('login.html'))
res.delete_cookie('token') # 删除key值
return res
@blue.route('/index/')
def index():
# 登录过后能看到index.html页面, 没有登录跳转到登录页面
token = request.cookies.get('token')
if token == '12345678':
# 判断登录成功了
return render_template('index.html')
else:
# 判断登录失败了
return render_template('login.html')
@blue.route('/session_login/', methods=['GET', 'POST'])
def session_login():
if request.method == 'GET':
return render_template('session_login.html')
if request.method == 'POST':
# 解析参数
username = request.form.get('username')
password = request.form.get('password')
if username == 'coco' and password == '123456':
# 向session会话中设置键值对, 1代表True
session['login_status'] = 1
# session['name'] = 'coco'
# session['pwd'] = '123456'
return redirect(url_for('first.index'))
else:
return render_template('session_login.html')
@blue.route('/session_index/')
@is_login
def session_index():
# if 'login_status' in session:
return redirect(url_for('first.index'))
# else:
# return render_template('session_login.html')
# 不用上面判断, 一步完成
@blue.route('/xindex/')
@is_login
def xindex():
# 登录过后能够访问index.html页面
# 没有登录不让访问,跳转到session.html页面
return redirect(url_for('first.index'))
@blue.route('/session_logout/')
def session_my_logout():
# 注销
del session['login_status']
# return render_template('session_login.html') # 重新渲染下页面
return redirect(url_for('first.session_login')) # 和上面一样
# 跳转到一个函数
@blue.route('/redirect_func/')
def redirect_func():
# 跳转到登录页面
# return render_template('login.html')
# return redirect('/login/') # 跳转到这个地址上面, 类似昨天的action
# url_for('蓝图第一个参数.跳转的函数名') 就可以不用写render_template()了
# return redirect(url_for('first.login')) # 蓝图第一个参数.函数名
# 无参跳转
# return redirect('/s_id/1/')
return redirect(url_for('first.s_id', id=1)) # 和上一步一样
# 的 这就是有参跳转
@blue.route('/s_id/<int:id>/')
def s_id(id):
return 's_id: %s' % id
# 模板内容
@blue.route('/student/')
def stu():
stus_score = [90, 89, 100, 99, 87, 67]
content2_h2 = '<h1>睡觉</h1>'
return render_template('stu.html', scores=stus_score, content2_h2=content2_h2)
上面文件中的is_login它是调用函数(为了简便,只在该页面需要一步操作,)
创建一个utils包,里面有init.py和functions.py文件
functions.py文件里是一个装饰器
functions.py文件中
from functools import wraps
from flask import session, render_template
# 装饰器
# 装饰器的三个条件:
# 1.外层函数嵌套内层函数
# 2.外层函数返回内层函数
# 3.内层函数调用外层函数的参数
# 下面最简单的装饰器结构:
def is_login(func):
@wraps(func) # 这步是让函数调用自己的本身(session_index),
而不是is_login
def check():
# 获取session是否登录那个值,假如没登录就异常捕获了,害怕报错
try:
session['login_status']
# 登录过后能够访问index.html页面
return func()
except:
# 没有登录不让访问,跳转到session.html页面
return render_template('session_login.html')
return check
if __name__ == '__main__':
pass
优化完之后在hello.py文件中是这样的
import redis # 这行是第三方库, 下面也是
from flask import Flask
from flask_script import Manager
from flask_session import Session
# from utils.functions import is_login # 自己写的包(可以删掉了)
from app.views import blue
app = Flask(__name__) # 生成app对象
# 第二步: 管理蓝图
app.register_blueprint(blueprint=blue) # 注册一下
# 设置secret_key加密, 加密复杂程度和设置有关,不能告诉别人的
# 此时存在cookie中的
app.secret_key = '1234567890'
# 没有登录不让访问,跳转到session.html页面ession.html页面
# 配置session的信息
# from flask_session import Session
app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_REDIS'] = redis.Redis(host='127.0.0.1', port=6379)
Session(app) # 会话
manage = Manager(app)
if __name__ == '__main__':
# app.run()
manage.run()
将导入的库变灰色的都删掉, 同时要导入
from app.views import blue
# 因为用了app.register_blueprint(blueprint=blue)这句
二 优化html文件
jinja2
通过父模板来优化, 可以让多个html文件同时使用一个父模板,这样就免得写很多相同的页面和样式。
flask使用操作指南之模板
1. jinja2
Flask中使用jinja2模板引擎
jinja2是由Flask作者开发,模仿Django的模板引擎
优点:
速度快,被广泛使用
HTML设计和后端python分离
非常灵活,快速和安全
提供了控制,继承等高级功能
2. 模板语法
2.1 模板语法主要分为两种:变量和标签
模板中的变量:{{ var }}
视图传递给模板的数据
前面定义出来的数据
变量不存在,默认忽略
模板中的标签:{% tag %}
控制逻辑
使用外部表达式
创建变量
宏定义
2.2 结构标签:
block
{% block xxx %}
{% endblock %}
块操作
父模板挖坑,子模板填坑
extends
{% extends ‘xxx.html’ %}
继承以后保留块中的内容
{{ super() }}
挖坑继承体现的化整为零的操作
macro
{% macro hello(name) %}
{{ name }}
{% endmacro %}
宏定义,可以在模板中定义函数,在其他地方调用
宏定义可导入
{% from 'xxx' import xxx %}
例子1:
在index.html中定义macro标签,定义一个方法,然后去调用方法,结果是展示商品的id和商品名称
{% macro show_goods(id, name) %}
商品id:{{ id }}
商品名称:{{ name }}
{% endmacro %}
{{ show_goods('1', '娃哈哈') }}
<br>
{{ show_goods('2', '雪碧') }}
例子2:
在index.html页面中定义一个say()方法,然后解析该方法:
{% macro say() %}
<h3>今天天气气温回升</h3>
<h3>适合去游泳</h3>
<h3>适合去郊游</h3>
{% endmacro %}
{{ say() }}
例子3:
定义一个function.html中定义一个方法:
{% macro create_user(name) %}
创建了一个用户:{{ name }}
{% endmacro %}
在index.html中引入function.html中定义的方法
{% from 'functions.html' import create_user %}
{{ create_user('小花') }}
2.3 循环
{% for item in cols %}
aa
{% else %}
bb
{% endfor %}
也可以获取循环信息loop
loop.first
loop.last
loop.index
loop.revindex
2.4 过滤器
语法:
{{ 变量|过滤器|过滤器... }}
capitalize 单词首字母大写
lower 单词变为小写
upper 单词变为大写
title
trim 去掉字符串的前后的空格
reverse 单词反转
format
striptags 渲染之前,将值中标签去掉
safe 讲样式渲染到页面中
default
last 最后一个字母
first
length
sum
sort
例子:
<ul>
<li>{{ content_h2 }}</li>
<li>{{ content_h2|safe }}</li>
<li>{{ content_h2|striptags }}</li>
<li>{{ content_h3 }}</li>
<li>{{ content_h3|length }}</li>
<li>{{ content_h3|trim|safe }}</li>
<li>{{ content_h3|trim|length }}</li>
</ul>
3. 定义模板
3.1 定义基础模板base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>
{% block title %}
{% endblock %}
</title>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
{% block extCSS %}
{% endblock %}
</head>
<body>
{% block header %}
{% endblock %}
{% block content%}
{% endblock %}
{% block footer%}
{% endblock %}
{% block extJS %}
{% endblock %}
</body>
</html>
3.2 定义基础模板base_main.html
{% extends 'base.html' %}
{% block extCSS %}
<link rel="stylesheet" href="{{
url_for('static', filename='css/mai
n.css') }}">
{% endblock %}
首先我们在templates创建base.html文件, base_main.html文件
base.html文件中
<!--此时这个页面是个框架, 父模板-->
<!--父模板挖坑, 子模板没必要都要填坑-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>
<!--jinja2 title是命名 俗称挖坑-->
{% block title %}
{% endblock %}
</title>
{% block css %}
{% endblock %}
{% block js %}
{% endblock %}
</head>
<body>
<!--content是命名-->
{% block content %}
{% endblock %}
</body>
</html>
base_main.html文件中
{% extends 'base.html' %}
<!--继承某个模板-->
<!--让每个页面都引用下面这个js-->
{% block js %}
<!--初始化引入juquery.js-->
<script src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
{% endblock %}
stu.html页面
<!--继承 网页上显示的是下面的页面的而不是stu了-->
<!--先继承 再填坑, 子模板没必要都填坑,没用就不填-->
<!--坑的名字必须唯一-->
<!--{{ a }} 就是在html上打印a 里面a是变量-->
{# {{ 注释 }} #}
{% extends 'base_main.html' %}
{% block title %}
学生列表页面
{% endblock %}
{% block css %}
<!--第一种写法-->
<!--<link rel="stylesheet" href="/static/css/style.css">-->
<!--第二种写法-->
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
{% endblock %}
{% block js %}
{{ super() }}
<script src="23231dewdde.js"></script>
{# {{ 此时不会显示base_main里面的js,因为只显示这个, 当加了{{ super() }}之后两个都会显示 }} #}
{% endblock %}
{% block content %}
<!--过滤器 | - 管道符 safe-加载样式 striptags取消标签-->
<p>{{ content2_h2 | safe }}</p>
<p>{{ 'Python' | length }}</p>
<p>{{ 'Python' | upper }}</p>
<p>{{ 'Python' | lower }}</p>
<p>{{ 'Python' | upper | length }}</p>
<p>{{ 'Python' | reverse }}</p>
<p>{{ content2_h2 | striptags }}</p>
<!--解析变量使用 {{ 变量名 }}-->
<p> {{ scores }} </p>
<!--解析标签, extends, block, for-->
<ul>
{% for a in scores %}
<!--显示列表的数字-从0开始(类似于下标) revindex倒着排序-->
{{ loop.index0 }}
<!--判断是否为第一个(是就为True,不是则为False)和最后一个-->
{{ loop.first }}
{{ loop.last }}
<li {% if loop.first == 1 %} style="color:yellow;" {% endif %}>
{{ a }}
</li>
{% else %}
<li>没有学生成绩数据</li>
{% endfor %}
</ul>
<table>
<thead>
<th>姓名</th>
<th>年龄</th>
</thead>
<tbody>
<tr>
<td>张三</td>
<td>28</td>
</tr>
<tr>
<td>李四</td>
<td>29</td>
</tr>
</tbody>
</table>
{% endblock %}
image.png