flask入门

1.入门程序

from flask import Flask

app = Flask(__name__)
app.run()

flask提供了自动重启服务的功能:调试模式

app.run(debug=True)

 

2.定义路由

@route('/user/<username>')

@route('/post/<int:uid>')

@route('/post/<float:price>')

@route('/post/<path:path>')

路由装饰器:

    def route(self, rule, **options):
        """Like :meth:`Flask.route` but for a blueprint.  The endpoint for the
        :func:`url_for` function is prefixed with the name of the blueprint.
        """
        def decorator(f):
            endpoint = options.pop("endpoint", f.__name__)
            self.add_url_rule(rule, endpoint, f, **options)
            return f
        return decorator

 

 

from flask import Flask

app = Flask(__name__)

# 视图函数
@app.route("/hello/") -->/hello /hello/
def hello():
return "hello world"

app.run()

基于类的视图(即插视图)

 

另一种注册路由的方式:app.add_url_rule("/hello", view_func=hello)

@app.route和app.add_url_rule参数:
            rule,                       URL规则
            view_func,                  视图函数名称
            defaults=None,              默认值,当URL中无参数,函数需要参数时,使用defaults={'k':'v'}为函数提供参数
            endpoint=None,              名称,用于反向生成URL,即: url_for('名称')
            methods=None,               允许的请求方式,如:["GET","POST"]
            

            strict_slashes=None,        对URL最后的 / 符号是否严格要求,
                                        如:
                                            @app.route('/index',strict_slashes=False),
                                                访问 http://www.xx.com/index/ 或 http://www.xx.com/index均可
                                            @app.route('/index',strict_slashes=True)
                                                仅访问 http://www.xx.com/index 
            redirect_to=None,           重定向到指定地址
                                        如:
                                            @app.route('/index/<int:nid>', redirect_to='/home/<nid>')
                                            或
                                            def func(adapter, nid):
                                                return "/home/888"
                                            @app.route('/index/<int:nid>', redirect_to=func)
            subdomain=None,             子域名访问
                                                from flask import Flask, views, url_for

                                                app = Flask(import_name=__name__)
                                                app.config['SERVER_NAME'] = 'wupeiqi.com:5000'


                                                @app.route("/", subdomain="admin")
                                                def static_index():
                                                    """Flask supports static subdomains
                                                    This is available at static.your-domain.tld"""
                                                    return "static.your-domain.tld"


                                                @app.route("/dynamic", subdomain="<username>")
                                                def username_index(username):
                                                    """Dynamic subdomains are also supported
                                                    Try going to user1.your-domain.tld/dynamic"""
                                                    return username + ".your-domain.tld"


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

 

 

反向构建URL

<img src="{{ url_for('static', filename='/js/jquery.js') }}" />

参数一:endpoint

 

3.配置文件

 

# 导入配置文件
app.config.from_object('app.secure')
app.config.from_object('app.setting')
app.config['DEBUG']    --配置文件的变量必须大写

在业务逻辑层使用配置文件:
  from flask import current_app
  current_app.config['KEY']

 


4.返回结果

4.1 json  【API】

对于基本类型:

  return flask.jsonify(data)    

对于对象类型:

  return json.dumps(obj, default=lambda o:o.__dict__)

 4.2 context-type:text/plain 返回纯文本

from flask import make_response 
# 默认 content-type:text/html
# 返回response对象
headers = {
'content-type':'application/json',
# 'content-type':'text/plain',
'location':'www.baidu.com'
}
response = make_response("hello wolrdd", 200)
response.headers = headers
# return response
# return 'hello flask', 200, headers

4.3 返回带cookie的页面

response = make_response(render_template('index.html'))
# response是flask.wrappers.Response类型
response.delete_cookie('key')
response.set_cookie('key', 'value')
response.headers['X-Something'] = 'A value'
return response

 

 

 

5.session

session['k']=value
# session.pop()

 

 

6.将视图函数拆分多个文件中

 

7.request参数

7.1  url?q=xxx&page=xxx形式的参数,【get请求】

  通过request对象获取请求参数:

from flask import request

request.args['q']   或 request.args.get('q')

request.args是不可变字典, 转化成可变字典:a = request.args.to_dict()

 

7.2 form post

request.form接受post请求参数

7.3 URL方式接受参数

@app.route('/detail/<int:uid>')

def detail(uid):

  pass

 

 

 

 

8.WTFroms参数验证,验证层

安装WTForms:pipenv install wtforms

from wtforms import Form, StringField, IntegerField
from wtforms.validators import Length, NumberRange, DataRequired


class SearchForm(Form):
    # DataRequired要求参数不能为空格
    q = StringField(validators=[DataRequired(message='关键字不能为空格'), Length(min=1,max=30, message='关键字的长度应该在1-30')])
    page = IntegerField(validators=[NumberRange(min=1, max=20)], default=1)

 自定义验证器:

业务需求:对邮箱进行验证,除了验证形式的合法性,还要验证数据库中是否存在

class RegisterForm(Form):
    email = StringField(validators=[DataRequired(), Length(8, 64), Email(message='邮箱格式不合法')])
    password = StringField(validators=[DataRequired(message='密码不能为空'), Length(6,32)])
    nickname = StringField(validators=[DataRequired(), Length(2, 10, message='昵称长度2-10')])

    # 这个函数由WTForm自动调用,field为email属性
    def validate_email(self, field):
        if User.query.filter_by(email=field.data).first():
            raise ValidationError('电子邮箱已经被注册')   # 如果不合法,抛出指定的异常

 

 

 

视图函数:

from flask import Flask, make_response, jsonify, request

from app.forms.book import SearchForm
from . import web


# 参数
@web.route('/book/search', methods=['GET', 'POST'])
def search():
    form = SearchForm(request.args)
    if form.validate():
        print('验证通过')
        q = form.q.data.strip()  #去空格
        page = form.page.data
        # 调用业务逻辑层
        result = {'q': q, 'page': page}
        return jsonify(result)
    else:
        print('验证失败')
        return jsonify(form.errors)

 

 

9.数据库操作【ORM】 code first  sqlalchemy ->flask_SQLAlchemy

安装flask_SQLAlchemy:pipenv install  flask-sqlalchemy

安装数据库驱动:mysq->cymysql  或者pymysql

from sqlalchemy import Column, Integer, String, Float


class Book(object):
    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)
    author = Column(String(20), nullable=False)
    price = Column(Float, nullable=True, default=0)
    isbn = Column(String(15), nullable=False, unique=True)
    summery = Column(String(200), default='没有简介')

 

10.AppContext, RequestContext, Flask, Request关系【LocalProxy】

 

  

12.模板渲染

render(html, data)

对于css、js文件,直接返回给客户端

 

13.静态文件【css,js,images..】和 模板文件【HTML】

Flask内部仍然使用路由、视图函数对静态文件进行返回。

 

静态文件的默认位置:__name__/static

模板文件的默认位置:__name__/templates

 

修改默认位置:

app = Flask(__name__, static_folder='view_model/static', templates_folder=' xxx ')  # 相对路径

 

模板文件也可以放在蓝图下面:在蓝图的__init__文件,Blueprint('web', templates_folder=' xxx')

14. 模板引擎:jinja2  【官网:http://jinja.pocoo.org/docs/2.10/

14.1 基本设置

  为了让IDE【pycharm】更友好点(定位模板页面的路径),将对应文件夹设置为模板文件夹:

  设置模板引擎:

   实例:

@web.route('/index', methods=['GET'])
def index():
    data = {
        'name':'张三',
        'age':20
    }
    return render_template('index.html', data=data)

 

对于字典和对象类型的data,可以使用点来访问,也可以使用索引

<body>
<div>
    <p>姓名:{{data.name}}</p>
    <p>年龄:{{data.age}}</p>
</div>
</body>

 字符串【raw】:默认字符串当做纯字符串

{% set str='<input type="text">' %}
{{ str }}

如果需要HTML解析的字符串,在后台使用Markup(‘’)构造

宏定义:

{% macro xx(name, type='text', value='') %}
    <input type="{{ type }}" name="{{ name }}" value="{{ value }}" />
{% endmacro %}
{{ xx('age') }}

 

 

14.2 流程控制语句

  所有的流程控制语句都要被包含在{%  %}内。

(1)条件判断语句

比较运算符、and 、or都可以使用

{% if data.age < 20 %}
    {{ data.name }}
{% elif data.age == 20 %}
     <p>年龄为 20</p>
{% else %}
    <p>年龄大于20</p>
{% endif %}

 

 

(2)循环语句

{% for i in range(5) %}
    <h3>{{ i }}</h3>
{% endfor %}

 

 

14.3 使用模板继承

模板页:layout.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>鱼书</title>
</head>
<body>
    {% block head %}
        head
    {% endblock %}
    
    {% block content %}
    content {% endblock %} {% block foot %} footer {% endblock %}
</body> </html>

 

继承模板页:

{% extends 'layout.html' %}

{% block content %}
    {{ super() }}
    <p>姓名:{{data.name}}</p>
    <p>年龄:{{data.age}}</p>
    {% if data.age < 20 %}
        {{ data.name }}
    {% elif data.age == 20 %}
         <p>年龄为 20</p>
    {% else %}
        <p>年龄大于20</p>
    {% endif %}

    {% for i in range(5) %}
        <h3>{{ i }}</h3>
    {% endfor %}

{% endblock %}

 

14.4 过滤器【filter】

default:

{{ data.name | default('未名',False) }}     如果不存在name属性,显示未名,【异常处理】
boolean=True => None,False, '', {}, [] -->default

str = False or 'hello' ->hello
str = None or 'hello' ->hello
str = '' or 'hello' ->hello

 length:

 {{ data | length() }}     输出data的长度

 

 

16.消息闪现

 

@web.route('/index', methods=['GET'])
def index():
    data = {
        'name':'张三',
        'age':20
    }
    flash('登录成功', category='ok')
    flash('成功进入系统', category='error')
    return render_template('index.html', data=data)

 

使用消息:

  使用set定义的变量,作用域为blocks的全局变量

{% set message = get_flashed_messages(category_filter='error') %}
{{ message }}

 

 

 19.密码加密 【werkzeug.security】

 from werkzeug.security import generate_password_hash

 

20.redirect重定向

redirect(url_for('web.login'))   # 蓝图名.endpoint

 

21.cookie

response = make_response()

response.set_cookie(key, value, timeout)

 

flask提供了管理登录的插件:pipenv install flask_login     帮助文档

  login_user(user)  并不是将用户的所有信息都保存到cookie下,而是只需要保存用户的唯一标识ID。因此,在User类中需要定义一个方法get_id(self): return self.id

或者让User继承UserMixin,该类提供了更多的登录相关的方法、属性。  

 

访问权限控制:插件装饰器

user.py

@login_manager.user_loader
def get_user(uid):
    return User.query.get(int(uid))

 

gift.py

@web.route('/my/gift')
@login_required
def my_gift():
    return 'my gift'

 

 

 

 

@web.route('/login', methods=['GET', 'POST'])
def login():
    form = LoginForm(request.form)
    if request.method == 'POST' and form.validate():
        user = User.query.filter_by(email=form.email.data).first()

        if user and user.check_password(form.password.data):
            # 使用登录管理器 管理登录
            login_user(user, remember=True)
            next = request.args.get('next')
            if not next or not next.startswith('/'):
                next = url_for('web.index')
            return redirect(next)
        else:
            flash('账号不存在或者密码错误')
    return render_template('auth/login.html', form=form)

 

posted @ 2018-07-13 13:15  fight139  阅读(198)  评论(0编辑  收藏  举报