flask日常梳理

2019-03-16  本文已影响0人  battleMonkey

1.日常flask报错(没secret_key)

# 解决: 未设置 SECRET_KEY
SECRET_KEY = 'asdfewfasdfeasdfe'

2.导入 import 技巧

from . import xxx # . 表示从当前位置 导入

3.python3.6技巧

# type:声明一个None对象的类型
redis_store = None # type:StrictRedis
# 这样可以使用 该 类型的 方法(pycharm可以有提示)

4.git提交空文件夹:gitkeep

在 要提交的 空文件夹 新建 .gitkeep文件 实现 提交 空文件夹 到 码云

5.session 以 redis 存储 配置 app 参数的一些探究

SESSION_PERMANENT = False/True      #  指定 session 在 浏览器 存储方式(默认值为True)

如果 TRUE
  -浏览器  session 生存时间 受 PERMANENT_SESSION_LIFETIME = timedelta(days=1)  影响

如果 False
  -浏览器  session 生存时间 为 关闭浏览器

无论 SESSION_PERMANENT 如何变化
redis存储session 生存时间 只受 PERMANENT_SESSION_LIFETIME = timedelta(days=1)  影响

6.session存储:

收到客户端的session创建请求, 则为此客户端创建一个session并且生成一个与此session相关联的session id,session id的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个session id将被在本次响应中返回给客户端保存。

7.返回网站图标的 视图函数的 三种返回方式

from flask import render_template, redirect, current_app, send_file
...
@index_blu.route("/favicon.ico")
def favicon():
    # redirect("/static/news/favicon.ico")
    # 返回图片
    # return current_app.send_static_file("news/favicon.ico")
    return send_file("/static/news/favicon.ico")

8. import . # 导入当前目录包下的 初始化文件 .init

9.json相关

-json_data = request.data
-json_dict = json.loads(json_data)   
# 两步,封装合为一步,即:
- dict_data = request.json
...
-jsonify(key1 = value1, key2 = value2 ...)

10.视图函数 的url地址,必须以"/"开头

# 抛出ValueError('url必须以斜杠开头')
raise ValueError('urls must start with a leading slash')   
  
# ValueError: url必须以斜杠开头
ValueError: urls must start with a leading slash         

即: 创建的蓝图对象 前缀 没有加 "/"

11.pycharm 快捷键

ctrl + d 复制 改行内容 到下一行

12.禁止 浏览器 缓存 js,方便实时调试修改js代码

13.验证码请求技巧:

为了防止 图片请求的uuid 多次 在 服务器端 存储,可以在 前端 做 设置

前端js:

// TODO 生成一个图片验证码的编号,并设置页面中图片验证码img标签的src属性**
var cur_id = ""  pre_id = ""**
function generateImageCode() {**
//1.生成一个随机字符串**
imageCodeId = generateUUID();**
//2.拼接图片url地址**
image_url = '/passport/image_code?cur_id='+imageCodeId + "&pre_id="+preimageCodeId**
//3.将地址设置到image标签的src属性中,为image_url**
$('.get_pic_code').attr('src',image_url)**
//4.记录上一次的编号**
preimageCodeId = imageCodeId**
//============================================================
//第一次前端变化:
<img src="/passport/image_code       ?
          cur_id=2b82b7ab-044e-4a89-b87c-62a508163fcb
          &amp;
          pre_id=""
          //(pre_id="" 为空,因为 pre_id = preimageCodeId,此时 preimageCodeId 未赋值)
    class="get_pic_code" onclick="generateImageCode()">
                                                            
//第二次前端变化:
<img src="/passport/image_code       ?
          cur_id=5cdfc91e-9e05-43b9-9f08-93d2b3902b29
          &amp;
          //此处等于上一次的值
          pre_id=2b82b7ab-044e-4a89-b87c-62a508163fcb "  
    class="get_pic_code" onclick="generateImageCode()">

后端:

@passport_blu.route('/image_code')
def get_image_code():
    cur_id = request.args.get('cur_id')
    pre_id = request.args.get('pre_id')
    # print("image_code:%s"%cur_id)
    # print("image_code:%s"%pre_id) # 第一次时 pre_id 为 空
    if not cur_id:
        abort(404)
    
    # 调用generate_captcha 获取 图片验证码编号 验证码值 图片(二进制)
    _, text, image_data = captcha.generate_captcha()
    
    try:
        redis_store.setex("image_code:%s"%cur_id, IMAGE_CODE_REDIS_EXPIRES, text)
        if pre_id:
            redis_store.delete("image_code:%s"%pre_id)
    except Exception as e:
        current_app.logger.error(e)
        abort(500)

    # response = make_response(image)
    # response.headers['Content-Type'] = 'image/jpg'

    return image_data

14.调用generate_captcha获取图片验证码编号验证码值图片(二进制)

_, text, image_data = captcha.generate_captcha()
# 解包成三个参数 name  text值  image_data 二进制图片数据

15.在 Flask 中,可以很方便的返回自定义状态码,实现不符合 http 协议的状态码

例如:status code: 666

16.startUML -> 一款数据库模型类 软件

17.pycharm的 git 更改密码 windows - 打开 设置 搜索 ->凭据,删除密码

18.flask session 默认保存 31天

19. app(host = 0.0.0.0,) 暂时 只有 这里 可以 用 0.0.0.0 表示绑定当前 所有 ip

20.不推荐使用 json.dumps 转成 JSON 字符串直接返回

因为返回的数据要符合 HTTP 协议规范,如果是 JSON 需要指定 content-type:application/json

21.redis_store.delete(key)

如果 key 不存在, 不会报错 ,只会 返回 0 即:受影响 行数 为 0

22.raise 和 aborn 区别???

23.获取当前时间:

from datetime import datetime
datetime.now()

24.logger

current_app.logger.debug()
# 不是 loggin

25. 定义登陆装饰器, 封装用户的登陆数据时, 使用 数据库 的 User 模型类时,需注意避免产生循环导包问题

# 装饰器进阶(登陆状态封装):
# 定义登陆装饰器, 封装用户的登陆数据:
def user_login_data(view_func):
    @wraps(view_func)                     # 需要导包  from functools import wraps
    def wrapper(*args, **kwargs):
        # 1. 从session中 取出用户的user_id
        user_id = session.get("user_id")

        # 2 通过user_id 取出 user 对象:
        user = None
        if user_id:
            try:
                # *** 防止 循环导包
                from info.models import User
                user = User.query.get(user_id)
            except Exception  as e:
                current_app.logger.error(e)
        # 3 将user数据 封装到g对象:
        g.user = user                              # 封装flask的user 到 g 对象
        return view_func(*args, **kwargs)
        
    return wrapper

26.form 表单:

如果方法是 post,后端 需要 request.form

如果方法是 get , 后端 使用 request.args 就行

原理:

  • 前端 GET表单数据提交 -> 不走 请求体
  • get:表单数据会被 以参数的形式:name1=value1&name2=value2
    附带在url?后面,再发送给服务器,并在url中显示出来。

27.cookie 最大 客户端 存储 单个4kb ,网站同源策略 最多12个

28. flask的路由 转换器(默认 六种, 写了七个 是因为 default = string)

系统自带转换器
DEFAULT_CONVERTERS = {
    'default':          UnicodeConverter,
    'string':           UnicodeConverter,
    'any':              AnyConverter,
    'path':             PathConverter,
    'int':              IntegerConverter,
    'float':            FloatConverter,
    'uuid':             UUIDConverter,
}
转换器 作用
default (string) 默认选项,接受除了斜杠之外的字符串
int 接受整数
float 接受浮点数
path 和string类似,不过可以接受带斜杠的字符串
any 匹配任何一种转换器
uuid 接受UUID字符串

其中, path 允许匹配的路径 包含 '/' 适合接收 所有前端发来的 "url路径"

​ 其余, 等同于 string

29.自定义参数类型(自定义转换器)

"""
- 背景:
  - 如果系统提供的int,float,等参数类型满足不了需求的时候,我们需要自定义
  - 之所以,int,float,path可以接收不同的数据类型,是因为,系统已经提供好对应的转换器了
- 自定义转换器格式
  - 1.定义类,继承自BaseConverter
  - 2.重写init方法
  - 3.初始化父类成员变量, 还有子类自己的规则
  - 4.将转换器类,添加到系统默认的转换器列表中

  需求: 接收三位整数
"""
from flask import Flask
from werkzeug.routing import BaseConverter

app = Flask(__name__)

# - 1.定义类,继承自BaseConverter
class MyRegexConverter(BaseConverter):
    #这样直接指定规则,不够灵活,具体应该匹配什么规则应该交给路由
    # regex = "\d{3}"

    # - 2.重写init方法,接收两个参数
    def __init__(self,map,regex):
        # - 3.初始化父类成员变量, 还有子类自己的规则
        super(MyRegexConverter, self).__init__(map)
        self.regex = regex

# - 4.将转换器类,添加到系统默认的转换器列表中
app.url_map.converters["re"] = MyRegexConverter

#打印输出所有的系统转换器列表
print(app.url_map.converters)

# =========================================================

#使用re('规则'),实际上是传递了两个参数,参数1: app.url_map,  参数2:括号中写的正则规则
# /  < re( r "\d{3}" ) : number  >    r: 正则用法,忽略"转意字符"
#  转换器   re (self,map,regex)

#匹配三位整数
@app.route('/<re("\d{3}"):number>')
def hello_world(number):
    return "the three number is %s"%number

#匹配四位整数
@app.route('/<re("\d{4}"):number>')
def get_four_number(number):
    return "the four number is %s"%number

#匹配一个手机号
@app.route('/<re("1[3-9]\d{9}"):phone>')
def get_phone_number(phone):
    return "the phone number is %s"%phone

if __name__ == '__main__':
    app.run(debug=True)

30. 静态文件

动态 web 应用也会需要静态文件,通常是 CSS 和 JavaScript 文件。理想状况下, 你已经配置好 Web 服务器来提供静态文件,但是在开发中,Flask 也可以做到。 只要在你的包中或是模块的所在目录中创建一个名为 static 的文件夹,在应用中使用 /static 即可访问。

31.flask ORM 生成器relationship 可以支持 append 添加 数据?!

32. flask_ORM 使用小技巧

try:
    filter = []
    if cid != 1:
    filter.append(News.category_id == cid)
    # -如果cid = 1 -> filter = []
    # filter: 解包 [] 为 空
    # -如果cid != 1 -> filter = [ (News.category_id == cid), ]
    # filter = [ (News.category_id == cid), ] 解包为 " News.category_id == cid "
    # 这种方法,可灵活的在 filter = [] 添加其他过滤参数
    
    # 1.查询 News.query 查询集 添加过滤条件 得出的过滤后查询集结果
    paginate= News.query.filter(*filter)\                  # paginate 在这里定义赋值
    # 2.以 News对象的创建时间 降序排列
   .order_by(News.create_time.desc())\
    # 3.排列后的结果 进行分页     最后 得到的 是一个 分页对象!!!
    .paginate(page,per_page,False)
     
except Exception as e:
    current_app.logger.error(e)
    return jsonify(errno=RET.DBERR ,errmsg="获取新闻列表失败")

# 分页对象的 使用:
totalPage = paginate.pages     # 分页后  得到的总页数         # paginate 在这里被使用
currentPage = paginate.page    # 分页后  目前的  页数
itemsObj_list = paginate.items # 当前页的所有 对象集合         # paginate 的items 记得 加 "s" 啊

33. 使用request时,最好要 确定 前端 传入的 数据 是什么 形式

$.ajax({
    url:'/passport/login',
    type:'post',
    data:JSON.stringify(params),
    contentType:'application/json', //传入的 数据 是 json
    headers:{'X-CSRFToken':getCookie('csrf_token')},
    success: function (resp) {
        //判断是否登陆成功
        if(resp.errno == '0'){
            window.location.reload()
        }else{
            alert(resp.errmsg);
        }
    }
})

...

$.get("/newsList", params, function (resp) {...} //没有 注明,可能为 args 传参

34. app.init 配置 csrf_token(添加请求钩子)

from flask_wtf.csrf import generate_csrf

...

# 使用请求钩子 拦截所有的请求, 通过在中cookie设置csrf_token
@app.after_request
def after_request(resp):
    resp.set_cookie("csrf_token", generate_csrf())
    return resp

# 使用CSRFProtect保护app
CSRFProtect(app)

35. 首页新闻页试图函数 思路

1>为什么 需要定义新的视图函数?

因为需要让 首页 /index局部刷新
不可能说 获取了 很多 新闻之后, 一刷新 都没了
所以需要 定义新的 视图函数

2>一个不错的info模板(推荐添加到pycharm快捷键) -> setting 搜索 live 可以找到 快捷键设置

# 功能 :首页新闻列表的获取
###########################
# -请求路径 :/newsList
# -请求方式 :GET
# -携带参数 :cid, page, per_page
# -返回值 :jsonify
############################

3>前端传回cid的作用: 可以区分不同的新闻分类导航栏, 去查询数据库:

# -cid = 1 ,表示 最新, 不能 给 新闻 设置 cid = 1 ,
# 而是 应该 查询 所有新闻 并根据 "创建时间" 倒序排列,才是 最新新闻分类

# -page 和 per_page作用:
# 为了 给 后端 的 查询函数 paginate(page, per_page, False)
    # 传递参数含义:
        # - page: 当前页数
        # - per_page: 每页 显示条数
        # - False: 参数错误 不报错

# 传回参数:
totalPage = paginate.pages # 查到的 数据 总页数
currentPage = paginate.page # 当前 传回数据 的页数(即前端发送request 请求的页数)
itemsObj_list = paginate.items # 当前页数的 对象 列表
上一篇 下一篇

猜你喜欢

热点阅读