Day17-flask2

1 session和cookie

Session和Cookie的结合使用,一般有两种存储方式:

第一种: session数据存储在客户端: Flask采用'secure cookie'方式保存session,即session数据是使用base64编码后保存在客户端的cookie中。也就是说无须依赖第三方数据库保存session数据。

第二种: session数据存储在服务端,分为以下三步骤:

步骤1: 当客户端发送请求到服务端的时候,服务端会校验请求中cookie参数中的sessionid值,如果cookie中不存在sessionid则认为客户端访问服务端时,是发起了一个新的会话。

步骤2: 如果是新的会话,则服务端会传递给客户端一个cookie,并在cookie中存储一个新的sessionid值,并将相关数据保存在session中。

步骤3: 客户端下次再发送请求的时候,请求上下文对象会携带cookie,通过校验cookie中的sessionid值,即可判断是否是同一会话。

步骤4: 如果校验会话是同一会话,则可以从session中获取到之前保存的数据。

访问者的标识问题服务器需要识别来自同一访问者的请求。这主要是通过浏览器的cookie实现的。 访问者在第一次访问服务器时,服务器在其cookie中设置一个唯一的ID号——会话ID(session)。 这样,访问者后续对服务器的访问头中将自动包含该信息,服务器通过这个ID号,即可区 隔不同的访问者。

官网文档地址

1.1. Cookie

概念:

a)客户端会话技术,浏览器的会话技术

b)数据全部存储在客户端中

c)存储使用的键值对结构进行存储

特性:
    支持过期时间
    默认会自动携带本网站的cookie
    不能跨域名
    不能跨浏览器

创建:

Cookie是通过服务器创建的Response来创建的

设置:set_cookie('key', value, max_ages='', expires='')

删除, 有三种删除方式

    1\. 直接清空浏览器的cookie
    2\. delete_cookie('key') 直接使用delete_cookie函数
    3\. set_cookie('key','',expires=0) 重新设置key的值为空,过期时间为0

获取:

在每次请求中,url都会向服务器传递Request,在request中可以获取到cookie的信息

request.cookies.get('name')

例子1,设置cookie:

import datetime

@blue.route('/setcookie/')
def set_cookie():
    temp = render_template('index.html')
    response = make_response(temp)
    outdate=datetime.datetime.today() + datetime.timedelta(days=30)
    # 设置cookie中的name的存在时长,设置为30天才过期  
    response.set_cookie('name','cocoococo',expires=outdate)
    return response

例子2,删除cookie中的值

@blue.route('/setcookie/')
def set_cookie():
    temp = render_template('index.html')
    response = make_response(temp)
    # 第一种方式,通过set_cookie去删除
    response.set_cookie('name','',expires=0)
    # 第二种方式,del_cookie删除
    response.del_cookie('name')
    return response

例子3,获取cookie中的值

@blue.route('/getcookie/')
def get_cookie():
    name=request.cookies.get('name')  
    return name

1.2. 将session数据存储在数据库

flask-session是flask框架的session组件

该组件则将支持session保存到多个地方

如:

redis:保存数据的一种工具,五大类型。非关系型数据库

memcached

mongodb

sqlalchmey:那数据存到数据库表里面

1.2.1 安装

pip install flask-session

如果指定存session的类型为redis的话,需要安装redis

pip install redis

1.2.2 语法

设置session:

session['key'] = value

读取session:

result = session['key'] :如果内容不存在,将会报异常

result = session.get('key') :如果内容不存在,将返回None

删除session:

session.pop('key')

清空session中所有数据:

session.clear()

1.2.2 使用

我们在初始化文件中创建一个方法,通过调用该方法来获取到Flask的app对象

def create_app():
    app = Flask(__name__)
    # SECRET_KEY 秘钥
    app.config['SECRET_KEY'] = 'secret_key'
    # session类型为redis
    app.config['SESSION_TYPE'] = 'redis'
    # 添加前缀
    app.config['SESSION_KEY_PREFIX'] = 'flask'

    # 加载app的第一种方式
    se = Session()
    se.init_app(app=app)
    #加载app的第二种方式
    Session(app=app)
    app.register_blueprint(blueprint=blue)

    return app

1.2.3 案例

定义一个登陆的方法,post请求获取到username,直接写入到redis中,并且在页面中展示出redis中的username

a)需要先启动redis,开启redis-server,使用redis-cli进入客户端

b)定义方法

@blue.route('/login/', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        username = session.get('username')
        return render_template('login.html', username=username)
    else:
        username = request.form.get('username')
        session['username'] = username

        return redirect(url_for('first.login'))

c)定义模板

<body>
<h3>欢迎:{{ username }}</h3>
<form action="" method="POST">
    用户名:<input type="text" name="username" placeholder="请输入你的名字">
    <input type="submit" value="提交">
</form>
</body>

d)redis中数据

[图片上传失败...(image-9503e7-1539087770774)]

注意:我们在定义app.config的时候指定了SESSION_KEY_PREFIX为flask,表示存在session中的key都会加一个前缀名flask

e) cookie和session的联系

[图片上传失败...(image-c21ba6-1539087770774)]

访问者在第一次访问服务器时,服务器在其cookie中设置一个唯一的ID号——会话ID(session)。 这样,访问者后续对服务器的访问头中将自动包含该信息,服务器通过这个ID号,即可区 隔不同的访问者。然后根据不同的访问者来获取其中保存的value值信息。

2. jinja2

Flask中使用jinja2模板引擎

jinja2是由Flask作者开发,模仿Django的模板引擎

优点:

速度快,被广泛使用

HTML设计和后端python分离

非常灵活,快速和安全

提供了控制,继承等高级功能

3. 模板语法

3.1 模板语法主要分为两种:变量和标签

模板中的变量:{{ var }}

视图传递给模板的数据

前面定义出来的数据

变量不存在,默认忽略

模板中的标签:{% tag %}

控制逻辑

使用外部表达式

创建变量

宏定义

3.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('小花') }}

3.3 循环

{% for item in cols %}

    aa

{% else %}

    bb

{% endfor %}

也可以获取循环信息loop

loop.first

loop.last

loop.index

loop.revindex

例子:

在视图(models.py)中定义一个视图函数:

@stu.route('/scores/')
def scores():

    scores_list = [21,34,32,67,89,43,22,13]

    content_h2 = '<h2>今天你们真帅</h2>'
    content_h3 = '   <h3>今天你们真帅</h3>   '

    return render_template('scores.html',
                           scores=scores_list,
                           content_h2=content_h2,
                           content_h3=content_h3)

(该视图函数,在下面讲解的过滤器中任然使用其返回的content_h2等参数)

首先: 在页面中进行解析scores的列表。题目要求:第一个成绩展示为红色,最后一个成绩展示为绿色,其他的不变

<ul>
   {% for score in scores %}
        {% if loop.first %}
            <li style="color:red;">{{ loop.revindex }}:{{ loop.index }}:{{ score }}</li>
        {% elif loop.last %}
            <li style="color:green;">{{ loop.revindex }}:{{ loop.index }}:{{ score }}</li>
        {% else %}
            <li> {{ loop.revindex }}:{{ loop.index }}:{{ score }}</li>
        {% endif %}
    {% endfor %}
</ul>

3.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>

4. 定义模板

4.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>

4.2 定义基础模板base_main.html

{% extends 'base.html' %}

{% block extCSS %}
    <link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
{% endblock %}

5. 静态文件信息配置

django

第一种方式:

{% load static %}
<link rel="stylesheet" href="{% static 'css/index.css' %}">

第二种方式:

<link rel="stylesheet" href="/static/css/index.css">

flask

第一种方式:

<link rel="stylesheet" href="/static/css/index.css">

第二种方式:

<link rel="stylesheet" href="{{ url_for('static', filename='css/index.css') }}">

6. Flask模型

Flask默认并没有提供任何数据库操作的API

我们可以选择任何适合自己项目的数据库来使用

Flask中可以自己的选择数据,用原生语句实现功能,也可以选择ORM(SQLAlchemy,MongoEngine)

SQLAlchemy是一个很强大的关系型数据库框架,支持多种数据库后台。SQLAlchemy提供了高层ORM,也提供了使用数据库原生SQL的低层功能。

ORM:

将对对象的操作转换为原生SQL
优点
    易用性,可以有效减少重复SQL
    性能损耗少
    设计灵活,可以轻松实现复杂查询
    移植性好

针对于Flask的支持,官网地址

pip install flask-sqlalchemy

安装驱动

pip install pymysql

7. 定义模型

使用SQLALchemy的对象去创建字段

其中tablename指定创建的数据库的名称

创建models.py文件,其中定义模型

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class Student(db.Model):

    s_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    s_name = db.Column(db.String(16), unique=True)
    s_age = db.Column(db.Integer, default=1)

    __tablename__ = "student"

其中:

Integer表示创建的s_id字段的类型为整形,

primary_key表示是否为主键

String表示该字段为字符串

unique表示该字段唯一

default表示默认值

autoincrement表示是否自增

8. 创建数据表

在视图函数中我们引入models.py中定义的db

from App.models import db

@blue.route("/createdb/")
def create_db():
    db.create_all()
    return "创建成功"

@blue.route('/dropdb/')
def drop_db():
    db.drop_all()
    return '删除成功'

其中: db.create_all()表示创建定义模型中对应到数据库中的表

db.drop_all()表示删除数据库中的所有的表

9. 初始化SQLALchemy

在定义的init.py文件中使用SQLALchemy去整合一个或多个Flask的应用

有两种方式:

第一种:

from flask_sqlalchemy import SQLALchemy

app = Flask(__name__)
db = SQLAlchemy(app)

第二种:

from App.models import db

def create_app():
    app = Flask(__name__)
    db.init_app(app)
    return app

10. 配置数据库的访问地址

官网配置参数

数据库连接的格式:

dialect+driver://username:password@host:port/database

dialect数据库实现

driver数据库的驱动

例子: 访问mysql数据库,驱动为pymysql,用户为root,密码为123456,数据库的地址为本地,端口为3306,数据库名称HelloFlask

设置如下: "mysql+pymysql://root:123456@localhost:3306/HelloFlask"

在初始化init.py文件中如下配置:

app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

app.config['SQLALCHEMY_DATABASE_URI'] = "mysql+pymysql://root:123456@localhost:3306/HelloFlask"

11.向表中添加数据

db.session.add(user)
db.session.commit()

12.加密解密

加密
generate_password_hash(密码)
解密
check_password_hash(数据库加密数据,前端上传数据)

manage.py

import redis
from flask import Flask
from flask_script import Manager
from flask_session import Session

from uers.models import db
from uers.views import uesrs_blue


app=Flask(__name__)
# 设置前缀users,使用url_prefix
app.register_blueprint(blueprint=uesrs_blue,url_prefix='/users')

# session配置
app.config['SESSION_TYPE']='redis'
app.config['SESSION_REDIS']=redis.Redis(host='127.0.0.1',port=6379)
# 设置秘钥SECRET_KEY
app.config['SECRET_KEY']='123'

# 数据库的配置
app.config['SQLALCHEMY_DATABASE_URI']='mysql+pymysql://root:123456@127.0.0.1:3306/flask5'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS']=False


# 获取Session对象,并初始化app
se=Session()
se.init_app(app)

# 绑定app和db
db.init_app(app)

manager=Manager(app=app)

if __name__=='__main__':
    manager.run()

users->models.py

from flask_sqlalchemy import SQLAlchemy


db=SQLAlchemy()


class User(db.Model):
    id=db.Column(db.Integer,primary_key=True,autoincrement=True)
    username=db.Column(db.String(10),unique=True,nullable=False)
    password=db.Column(db.String(128),nullable=False)

    __tablename__='user'



users->views.py

from flask import Blueprint, render_template, request,\
    redirect, session, url_for
from werkzeug.security import generate_password_hash, check_password_hash

from uers.models import db, User
from utils.functions import is_login


uesrs_blue=Blueprint('users',__name__)


@uesrs_blue.route('/login/',methods=['GET','POST'])
def login():
    if request.method=='GET':
        return render_template('login.html')
    if request.method=='POST':
        username=request.form.get('username')
        password=request.form.get('password')
        # 校验用户不能为空
        if not all([username,password]):
            return render_template('login.html')
        user=User.query.filter_by(username=username).first()
        if user:
            pwd=user.password
            if check_password_hash(pwd,password):
                session['login_status'] = 1
                return redirect(url_for('users.index'))
        else:
            return render_template('login.html')


@uesrs_blue.route('/index/',methods=['GET','POST'])
@is_login
def index():
    return render_template('index.html')


@uesrs_blue.route('/session_delete/')
def session_delete():
    session.clear()
    return render_template('login.html')


@uesrs_blue.route('/scores/',methods=['GET'])
def scores():
    # django 中的render
    # render('scores',{'stu_scores':stu_scores,'content_h2':content_h2})
    stu_scores=[80,56,31,89,76,34]
    content_h2='<h2> hello python </h2>'
    return render_template('scores.html',
                           stu_scores=stu_scores,
                           content_h2=content_h2)


@uesrs_blue.route('/create_db/')
def create_db():
    db.create_all()
    return '创建成功'


@uesrs_blue.route('/register/',methods=['GET','POST'])
def register():
    if request.method=='GET':
        return  render_template('register.html')
    if request.method=='POST':
        username=request.form.get('username')
        password=request.form.get('password')
        if not all([username,password]):
            return render_template('register.html')
        # 保存注册信息
        pwd=generate_password_hash(password)
        user=User()
        user.username=username
        user.password=pwd
        # 保存
        db.session.add(user)
        db.session.commit()
        return redirect(url_for('users.login'))

templates->base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>
        {% block title %}
        {% endblock %}
    </title>
    {% block css %}
    {% endblock %}

    {% block js %}
    {% endblock %}
</head>
<body>
{% block content %}
{% endblock %}
</body>
</html>

templates->base_main.html

{% extends 'base.html' %}
{% block js %}
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"type="text/javascript"></script>
{% endblock %}


templates->register.html

{% extends 'base_main.html' %}
{% block title %}
注册
{% endblock %}
{% block content %}
<form action="" method="post">
    姓名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit" value="注册">
</form>
{% endblock %}

templates->login.html

{% extends 'base_main.html' %}
{% block title %}
    登录
{% endblock %}

{% block js %}
    {{ super() }}
    <!--第一种:引入js-->
    <!--<script src="/static/js/style.js"></script>-->
    {# 第二中:Django中{% static 'xxx.js' %} #}
    <script src="{{ url_for('static',filename='js/style.js')}}"></script>
{% endblock %}

{% block content %}
<form action="" method="post">
    姓名:<input type="text"name="username"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit" value="登录">
</form>
{% endblock %}

templates->index.html

{% extends 'base_main.html' %}
{% block title %}
首页
{% endblock %}

{% block js %}
{{ super() }}
{% endblock %}

{% block content %}
    lala
{% endblock %}

templates->functions.html

<!--宏定义,定义函数,无参情况-->
{% macro hello() %}
    <p>你好,兄弟</p>
{% endmacro %}


<!--宏定义:有参情况-->
{% macro say(name,age) %}
    <p>你好,{{name}},{{age}}</p>
{% endmacro %}


templates->scores.html

{% extends 'base_main.html' %}
{% block title %}
成绩
{% endblock %}
{% block content %}
    <!--宏定义,定义函数,无参情况-->
    {% from 'functions.html' import hello , say %}
    {{ hello() }}
    <!--宏定义:有参情况-->
    {{ say('小李',15) }}
    {# {{ say('小李','18','男','address:天祥广场') }} #}

    {{ content_h2 | safe }}
    {{ content_h2 | safe | length }}
    <!--去掉p标签-->
    {{ content_h2 | striptags}}
    {{ content_h2 | striptags | capitalize | title | lower |upper}}
    {{ stu_scores }}<br>
    {% for score in stu_scores %}
    <!--jinja2中没有ifequal,loop不能在for循环外使用,只能在for循环中使用-->
    <p {% if loop.first %} style="color:red"{% endif %}>
            序号:{{ loop.index0 }}
            成绩:{{ score }}
            循环:{{loop.first}}
        </p>
    {% endfor %}
{% endblock %}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,874评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,102评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,676评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,911评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,937评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,935评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,860评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,660评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,113评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,363评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,506评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,238评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,861评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,486评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,674评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,513评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,426评论 2 352

推荐阅读更多精彩内容