flask簡單瞭解

Flask簡介:html

  Flask是一個Python編寫的Web 微框架,讓咱們可使用Python語言快速實現一個網站或Web服務,在介紹Flask以前首先來聊下它和Django的聯繫以及區別,django個大而全的web框架,它內置許多模塊,flask是一個小而精的輕量級框架,Django功能大而全,Flask只包含基本的配置 Django的一站式解決的思路,能讓開發者不用在開發以前就在選擇應用的基礎設施上花費大量時間。Django有模板,表單,路由,認證,基本的數據庫管理等等內建功能。與之相反,Flask只是一個內核,默認依賴於兩個外部庫: Jinja2 模板引擎和 Werkzeug WSGI 工具集,其餘不少功能都是以擴展的形式進行嵌入使用,相比於其餘Web框架例如Django,更加靈活也更加簡潔,以下幾行代碼就能夠寫出一個小程序:前端

複製代碼
from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello Flask!'

if __name__ == '__main__':
    app.run()
複製代碼

接下來咱們按照執行順序來了解下Flaskhtml5

配置文件python

app.config.from_object("settings.DevelopmentConfig") 


 

路由

  路由經過使用Flask的app.route裝飾器來設置web

動態路由(url傳參)ajax

複製代碼
@app.route('/user/<username>')
def show_user_profile(username):
    # show the user profile for that user
    return 'User %s' % username

@app.route('/post/<int:post_id>')
def show_post(post_id):
    # show the post with the given id, the id is an integer
    return 'Post %d' % post_id
複製代碼

若是但願獲取/article/1這樣的路徑參數,就須要使用路徑變量。路徑變量的語法是/path/<converter:varname>。在路徑變量前還可使用可選的轉換器,有如下幾種轉換器。redis

轉換器 做用
string 默認選項,接受除了斜槓以外的字符串
int 接受整數
float 接受浮點數
path 和string相似,不過能夠接受帶斜槓的字符串
any 匹配任何一種轉換器
uuid 接受UUID字符串

 

 

 

 

 

 

 

HTTP方法sql

若是須要處理具體的HTTP方法,在Flask中也很容易,使用route裝飾器的methods參數設置便可。數據庫

  • GET 將未經加密的信息發送的服務器. 是最通用的方法.
  • HEAD 該方法除了服務端不返回響應內容只返回頭信息以外, 同GET是同樣的.
  • POST 用於向服務器發送HTML表單數據. POST請求不會被緩存.
  • PUT 將URL所指示的資源用上傳的內容替換.
  • DELETE 將URL所指示的資源刪除.
複製代碼
from flask import request,render_template

@app.route('/login', methods=['GET', 'POST'])    #若是不加methods,Flask路由默認處理的是GET請求 def login():
    if request.method == 'POST':
        do_the_login()
    else:
        return render_template('xxx.html')
複製代碼

 

url_for 和 endpointdjango

複製代碼
from flask import Flask,url_for
app=Flask(__name__)
@app.route('/<path:url>',endpoint='XXX')        #endpoint默認爲函數名 def demo(url):
    print(url_for('XXX',url=url)) #若是設置了url參數,url_for(別名,加參數)
    return 'Hello World'

if __name__ == '__main__':
    app.run()
複製代碼

 

處理請求

Request 對象

Request 對象是一個全局對象,利用它的屬性和方法,咱們能夠方便的獲取從頁面傳遞過來的參數。

request.method 獲取請求方法
request.form 獲取POST類型的表單提交的數據和ajax請求的數據
request.args 獲取get請求參數 
request.values 獲取GET和POST請求攜帶的全部參數(GET/POST通用)
request.cookies 獲取cookies信息
request.headers 獲取請求頭信息
request.path 獲取cookies信息
request.full_path 獲取獲取用戶訪問的完整url地址+參數 例如(/index/?page=1)
request.url 獲取完整路徑
request.base_url 獲取訪問url地址(不獲取參數),例如 http://127.0.0.1:5000/;
request.files 獲取用戶上傳的文件

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

響應處理

 

  • 返回字符串   ----return 「asdf」    
  • 返回模板       ----return render_template('xxx.html')   
  • 返回重定向   ----return redirect(' /')
  • 返回字典       ----jsonify({'k1':'v1'})

  默認的錯誤頁面是一個空頁面,若是須要自定義錯誤頁面,可使用errorhandler裝飾器。

from flask import render_template

@app.errorhandler(404)
def page_not_found(error):
    return render_template('page_not_found.html'), 404

  咱們也能夠本身決定如何設置響應對象,方法也很簡單,使用make_response函數便可。

@app.errorhandler(404)
def not_found(error):
    resp = make_response(render_template('error.html'), 404)
    resp.headers['X-Something'] = 'A value'
    return resp

 

session

    咱們可使用全局對象session來管理用戶會話。Sesison 是創建在 Cookie 技術上的,不過在 Flask 中,咱們還能夠爲 Session 指定密鑰,這樣存儲在 Cookie 中的信息就會被加密,從而更加安全。

 

複製代碼
from flask import Flask, session, redirect, url_for, escape, request

app = Flask(__name__)
app.secret_key = 'qwertyuiop'
@app.route('/')
def index():
    if 'username' in session:
        return 'Logged in as %s' % escape(session['username'])
    return 'You are not logged in'

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        session['username'] = request.form['username']
        return redirect(url_for('index'))
    return '''
        <form method="post">
            <p><input type=text name=username>
            <p><input type=submit value=Login>
        </form>
    '''
@app.route('/logout')
def logout():
    # remove the username from the session if it's there
    session.pop('username', None)
    return redirect(url_for('index'))
複製代碼

 

Blueprint

  - 目錄結構劃分
  - 前綴
  - 特殊裝飾

- 某一類url添加前綴url_prefix
@h.route('',methods=[],url_prefix='')
- 給一類url添加before_request

 

 

 

 

 

特殊裝飾器

app.before_request 修飾器在開發中用處很是大,好比判斷某個ip是否有惡意訪問行爲,從而進行攔截等操做。

app.after_request 修飾器是在用戶請求獲得函數響應後被執行,不過須要注意的是這個執行是在函數返回數據前被調用,即請求已經被app.route修飾的函數響應過了,已經造成了response,但還未返回給用戶的時候,調用的。

複製代碼
from flask import Flask, Request, render_template
app = Flask(__name__, template_folder='templates')
app.debug = True


@app.before_first_request  #第1個請求到來執行
def before_first_request():
    print('before_first_request')


@app.before_request     #在進入視圖前執行
def before_request():
   if request.path=='/login':
      return None    if session['user']:
      return None
   return redirect('/login') 
   @app.errorhandler(404) def page_not_found(error): return 'This page does not exist', 404 @app.route('/index') def index(): return "Hello World" @app.after_request #視圖以後執行 def after_request1(response): print('after_request1', response) return response @app.after_request #先執行 after_request2 def after_request2(response): print('after_request2', response) return response if __name__ == '__main__': app.run()
複製代碼

 

模板

  使用方式和Django的模板渲染相似:{{ }} 和 {% %}。

  基本方法不太同樣,函數須要加括號執行,相似於python的語法:

    - {{ dict.get() }} 或 {{ dict["key"] }}

    - {{ list[0] }}

    - {% for 循環 %} {% endfor %}

    - {% if 判斷 %} {% endif %}

  還能夠自定義全局函數,在模板中使用:

複製代碼
@app.template_global()
def sum(a1, a2):
    return a1 + a2
# 模板中使用{{ sum(2, 3) }}

# 相似的
@app.template_filter()
def sum(a1, a2, a3):
    return a1 + a2 + a3
# 調用方式不一樣{{ 1|sum(2,3) }}   
複製代碼

  模板繼承:

複製代碼
{% extends "base.html"%}

{% block content %}
    自定義內容
{% endblock %}

{% include "組件.html" %}    
複製代碼

  定義宏:

複製代碼
{% macro input(name, type='text', value=' ') %}
<input type="{{ type }}" name="{{ name }}" value="{{ value }}">
{% endmacro %}

# 使用
<form>
{{ input('username') }}
{{ input('password', type="password") }}
{{ input(' ', type="submit", value="提交") }}
</form>
複製代碼

  安全:

複製代碼
# 前端
{{ data|safe }}

# 後端
from flask import Markup
data = Markup(data)
複製代碼

 

Flash

 

  flask中暫時儲存數據的一個方式

複製代碼
from flask import flash, get_flashed_messages

# 儲存數據
flash("臨時數據", "name")

# 獲取數據, 經過pop獲取並移除
msg = get_flashed_messages(category_filter=["name"])
複製代碼

 

wtforms

  安裝:pip3 install wtforms 

用戶登陸註冊示例

1. 用戶登陸

當用戶登陸時候,須要對用戶提交的用戶名和密碼進行多種格式校驗。如:

用戶不能爲空;用戶長度必須大於6;

密碼不能爲空;密碼長度必須大於12;密碼必須包含 字母、數字、特殊字符等(自定義正則);

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from flask import Flask, render_template, request, redirect
from wtforms import Form
from wtforms.fields import core
from wtforms.fields import html5
from wtforms.fields import simple
from wtforms import validators
from wtforms import widgets

app = Flask(__name__, template_folder='templates')
app.debug = True


class LoginForm(Form):
    name = simple.StringField(
        label='用戶名',
        validators=[
            validators.DataRequired(message='用戶名不能爲空.'),
            validators.Length(min=6, max=18, message='用戶名長度必須大於%(min)d且小於%(max)d')
        ],
        widget=widgets.TextInput(),
        render_kw={'class': 'form-control'}

    )
    pwd = simple.PasswordField(
        label='密碼',
        validators=[
            validators.DataRequired(message='密碼不能爲空.'),
            validators.Length(min=8, message='用戶名長度必須大於%(min)d'),
            validators.Regexp(regex="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&])[A-Za-z\d$@$!%*?&]{8,}",
                              message='密碼至少8個字符,至少1個大寫字母,1個小寫字母,1個數字和1個特殊字符')

        ],
        widget=widgets.PasswordInput(),
        render_kw={'class': 'form-control'}
    )



@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        form = LoginForm()
        return render_template('login.html', form=form)
    else:
        form = LoginForm(formdata=request.form)
        if form.validate():
            print('用戶提交數據經過格式驗證,提交的值爲:', form.data)
        else:
            print(form.errors)
        return render_template('login.html', form=form)

if __name__ == '__main__':
    app.run()
app
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from flask import Flask, render_template, request, redirect
from wtforms import Form
from wtforms.fields import core
from wtforms.fields import html5
from wtforms.fields import simple
from wtforms import validators
from wtforms import widgets

app = Flask(__name__, template_folder='templates')
app.debug = True


class LoginForm(Form):
    name = simple.StringField(
        label='用戶名',
        validators=[
            validators.DataRequired(message='用戶名不能爲空.'),
            validators.Length(min=6, max=18, message='用戶名長度必須大於%(min)d且小於%(max)d')
        ],
        widget=widgets.TextInput(),
        render_kw={'class': 'form-control'}

    )
    pwd = simple.PasswordField(
        label='密碼',
        validators=[
            validators.DataRequired(message='密碼不能爲空.'),
            validators.Length(min=8, message='用戶名長度必須大於%(min)d'),
            validators.Regexp(regex="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&])[A-Za-z\d$@$!%*?&]{8,}",
                              message='密碼至少8個字符,至少1個大寫字母,1個小寫字母,1個數字和1個特殊字符')

        ],
        widget=widgets.PasswordInput(),
        render_kw={'class': 'form-control'}
    )



@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        form = LoginForm()
        return render_template('login.html', form=form)
    else:
        form = LoginForm(formdata=request.form)
        if form.validate():
            print('用戶提交數據經過格式驗證,提交的值爲:', form.data)
        else:
            print(form.errors)
        return render_template('login.html', form=form)

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

2.註冊

from flask import Flask, render_template, request, redirect
from wtforms import Form
from wtforms.fields import core
from wtforms.fields import html5
from wtforms.fields import simple
from wtforms import validators
from wtforms import widgets

app = Flask(__name__, template_folder='templates')
app.debug = True



class RegisterForm(Form):
    name = simple.StringField(
        label='用戶名',
        validators=[
            validators.DataRequired()
        ],
        widget=widgets.TextInput(),
        render_kw={'class': 'form-control'},
        default='alex'
    )

    pwd = simple.PasswordField(
        label='密碼',
        validators=[
            validators.DataRequired(message='密碼不能爲空.')
        ],
        widget=widgets.PasswordInput(),
        render_kw={'class': 'form-control'}
    )

    pwd_confirm = simple.PasswordField(
        label='重複密碼',
        validators=[
            validators.DataRequired(message='重複密碼不能爲空.'),
            validators.EqualTo('pwd', message="兩次密碼輸入不一致")
        ],
        widget=widgets.PasswordInput(),
        render_kw={'class': 'form-control'}
    )

    email = html5.EmailField(
        label='郵箱',
        validators=[
            validators.DataRequired(message='郵箱不能爲空.'),
            validators.Email(message='郵箱格式錯誤')
        ],
        widget=widgets.TextInput(input_type='email'),
        render_kw={'class': 'form-control'}
    )

    gender = core.RadioField(
        label='性別',
        choices=(
            (1, ''),
            (2, ''),
        ),
        coerce=int
    )
    city = core.SelectField(
        label='城市',
        choices=(
            ('bj', '北京'),
            ('sh', '上海'),
        )
    )

    hobby = core.SelectMultipleField(
        label='愛好',
        choices=(
            (1, '籃球'),
            (2, '足球'),
        ),
        coerce=int
    )

    favor = core.SelectMultipleField(
        label='喜愛',
        choices=(
            (1, '籃球'),
            (2, '足球'),
        ),
        widget=widgets.ListWidget(prefix_label=False),
        option_widget=widgets.CheckboxInput(),
        coerce=int,
        default=[1, 2]
    )

    def __init__(self, *args, **kwargs):
        super(RegisterForm, self).__init__(*args, **kwargs)
        self.favor.choices = ((1, '籃球'), (2, '足球'), (3, '羽毛球'))

    def validate_pwd_confirm(self, field):    #局部鉤子,全局鉤子爲 def validate()
        """
        自定義pwd_confirm字段規則,例:與pwd字段是否一致
        :param field: 
        :return: 
        """
        # 最開始初始化時,self.data中已經有全部的值

        if field.data != self.data['pwd']:
            # raise validators.ValidationError("密碼不一致") # 繼續後續驗證
            raise validators.StopValidation("密碼不一致")  # 再也不繼續後續驗證


@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'GET':
        form = RegisterForm(data={'gender': 1})
        return render_template('register.html', form=form)
    else:
        form = RegisterForm(formdata=request.form)
        if form.validate():
            print('用戶提交數據經過格式驗證,提交的值爲:', form.data)
        else:
            print(form.errors)
        return render_template('register.html', form=form)



if __name__ == '__main__':
    app.run()
register app
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>用戶註冊</h1>
<form method="post" novalidate style="padding:0  50px">
    {% for item in form %}
    <p>{{item.label}}: {{item}} {{item.errors[0] }}</p>
    {% endfor %}
    <input type="submit" value="提交">
</form>
</body>
</html>
register.html

 

flask-session組件

在app的__init__中

複製代碼
from flask import Flask
from flask_session import Session

# 第一步:導入並實例化SQLAlchemy
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()

from .views.account import ac
from .views.user import us

from .models import *

def create_app():
    app = Flask(__name__)
    app.config.from_object('settings.Config')

    app.register_blueprint(ac)
    app.register_blueprint(us)

    # Flask-Session: 第一步示例Session
    # Session(app)

    # 第三步:依賴app中的配置文件
    db.init_app(app)

    return app
複製代碼

在settings中

class Config(object): 
      #配置
  SESSION_TYPE = 'redis'   SESSION_REDIS = Redis(host='192.168.0.94', port='6379')
  SECRET_KEY='QWERT' #使用session,必須配置secret_key 不然會報錯
相關文章
相關標籤/搜索