Flask框架整理及配置文件


 


Flask基礎部分

Flask目錄結構(藍圖)

views中存放藍圖,每個藍圖也可以有自己的模板,用藍圖對不同功能的視圖函數進行隔離,類似於django中的app

pro_flask包的init.py文件, 用於注冊所有的藍圖

復制代碼
from flask import Flask
from pro_flask.views.user import user
from pro_flask.views.blog import blog

app = Flask(name, template_folder='templates')
app.register_blueprint(user)
app.register_blueprint(blog)
app.secret_key
= "alex"

復制代碼

manage.py文件,作為整個項目的啟動文件

復制代碼
from pro_flask import app
from flask_script import Manager
from flask_bootstrap import Bootstrap

Bootstrap(app)
manage = Manager(app)
if name == 'main':
# app.call()
manage.run()

復制代碼

views包中的blog.py,必須要通過session驗證才能訪問,否則回到登錄界面

復制代碼
from flask import Blueprint, session, redirect, url_for, render_template

blog = Blueprint("blog", name, template_folder='templates')

@blog.route("/index/")
def index():
return render_template("index.html")

@blog.before_request # 請求該藍圖中所有的函數時都會先走這兒!
def process_request():
val
= session.get("login")
if val:
return None
else:
return redirect(url_for("user.login")) # 如果沒有session則阻斷請求

復制代碼

views包中的user.py,定義一些與用戶相關的視圖函數

復制代碼
from flask import Blueprint, render_template, request, session, url_for, redirect
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, EqualTo, Length, ValidationError

user = Blueprint("user", name, template_folder='templates')

@user.route("/login/", methods=["GET", "POST"])
def login():
if request.method == "POST":
username
= request.form.get("username")
password
= request.form.get("password")
if username == "alex" and password == "123":
session[
"name"] = "alex"
session[
"password"] = "123"
session[
"login"] = 1
return redirect(url_for("blog.index"))
return render_template("login.html")

@user.route("/logout/")
def logout():
session.pop(
"login")
return render_template("base.html")

class Register(FlaskForm):
  # username為表單中input中name屬性對應的值, "用戶名"為label的內容, balidators為驗證器(寫一些驗證表單內容的規則)
username
= StringField("用戶名", validators=[DataRequired("用戶名不能為空"), # 表單的驗證器
Length(min
=6, max=12, message="長度需要在6~12個字符之間")])
password
= PasswordField("密碼", validators=[DataRequired("密碼不能為空"),
Length(min
=6, max=12, message="密碼長度需要在6~12個字符之間")])
confirm
= PasswordField("確認密碼", validators=[DataRequired("密碼不能為空"), EqualTo("password", message="兩次輸入的密碼不一致")])
submit
= SubmitField("注冊")

</span><span style="color: #0000ff;">def</span><span style="color: #000000;"> validate_username(self, field):
    </span><span style="color: #0000ff;">if</span> self.username.data == <span style="color: #800000;">"</span><span style="color: #800000;">alex</span><span style="color: #800000;">"</span><span style="color: #000000;">:
        </span><span style="color: #0000ff;">raise</span> ValidationError(<span style="color: #800000;">"</span><span style="color: #800000;">該用戶已存在</span><span style="color: #800000;">"</span><span style="color: #000000;">)

@user.route("/register/", methods=["GET", "POST"])
def register():
form
= Register()
if form.validate_on_submit():
return redirect(url_for("user.login"))
return render_template("register.html", form=form)

復制代碼

加載靜態資源的方法

{{ url_for('static',filename='路徑/文件名稱.css/js/jpg') }}

實例:

{% block metas %}
    {{ super() }}
    <link rel="icon" href="{{ url_for('static',filename='img/1.jpeg',_external=True) }}">
{% endblock %}

Flask原碼部分理解

app.run()方法,負責啟動項目,監聽請求,那么它在內部做了哪些操作呢???

def run(self):
    ...
   from werkzeug.serving import run_simple
   run_simple(host, port, self, **options) # 第三個參數self指的是app這個對象自己
   ...

以上是原碼中app的run方法的部分內容,其實它執行的是run_simple這個方法

第三個參數將被反射調用,那么app(),就是去執行了app.__call__()方法

可以看出__call__方法其實是在調用wsgi_app這個接口

那么也就是說,將請求相關的所有內容都封裝到了一個類的對象中

ctx = self.request_context(environ) # 此時的ctx就是請求的對象

跟進_request_ctx_stack

可以看出將那個請求對象push進了這個LocalStack類的對象里,跟進到LocalStack()中

找到這個push方法,這里的obj就是那個請求的對象

 _local是在類初始化時,實例化的Local對象,反射這個Local對象中是否有stack這個屬性或方法,如果沒有,則執行_local.stack = [], rv = []

在rv列表中把那個請求對象加進來,而_local.stack = [],會觸發Local里面的__setattr__方法,所以跟進到Local中查看,Local的實現原理類似於threading.Local

復制代碼
 
          
try:
from greenlet import getcurrent as get_ident # 如果有協程庫,那么就支持協程
except ImportError:
try:
from thread import get_ident
except ImportError:
from _thread import get_ident # 支持線程
class Local(object):
    __slots__ = ('__storage__', '__ident_func__')
</span><span style="color: #0000ff;">def</span> <span style="color: #800080;">__init__</span><span style="color: #000000;">(self):
    object.</span><span style="color: #800080;">__setattr__</span>(self, <span style="color: #800000;">'</span><span style="color: #800000;">__storage__</span><span style="color: #800000;">'</span><span style="color: #000000;">, {})  # 使用這種方法不會觸發下面的__setattr__方法,避免遞歸
    object.</span><span style="color: #800080;">__setattr__</span>(self, <span style="color: #800000;">'</span><span style="color: #800000;">__ident_func__</span><span style="color: #800000;">'</span><span style="color: #000000;">, get_ident)# 將獲取唯一協程標識的方法賦值給了</span>__ident_func__</pre>
   def __getattr__(self, name):
        try:
            return self.__storage__[self.__ident_func__()][name]
        except KeyError:
            raise AttributeError(name)

    def __setattr__(self, name, value):
        ident = self.__ident_func__()
        storage = self.__storage__
        try:
            storage[ident][name] = value # 為每個協程/線程開辟空間,如果未開辟 則執行下面的代碼
        except KeyError:
            storage[ident] = {name: value}

    def __delattr__(self, name):
        try:
            del self.__storage__[self.__ident_func__()][name]
        except KeyError:
            raise AttributeError(name)
復制代碼

 

 


配置文件的參數

flask中的配置文件是一個flask.config.Config對象(繼承字典),默認配置為:

復制代碼
{
'DEBUG': get_debug_flag(default=False), 是否開啟Debug模式
'TESTING': False, 是否開啟測試模式
'PROPAGATE_EXCEPTIONS': None, 
'PRESERVE_CONTEXT_ON_EXCEPTION': None,
'SECRET_KEY': None,
'PERMANENT_SESSION_LIFETIME': timedelta(days=31),
'USE_X_SENDFILE': False,
'LOGGER_NAME': None,
'LOGGER_HANDLER_POLICY': 'always',
'SERVER_NAME': None,
'APPLICATION_ROOT': None,
'SESSION_COOKIE_NAME': 'session',
'SESSION_COOKIE_DOMAIN': None,
'SESSION_COOKIE_PATH': None,
'SESSION_COOKIE_HTTPONLY': True,
'SESSION_COOKIE_SECURE': False,
'SESSION_REFRESH_EACH_REQUEST': True,
'MAX_CONTENT_LENGTH': None,
'SEND_FILE_MAX_AGE_DEFAULT': timedelta(hours=12),
'TRAP_BAD_REQUEST_ERRORS': False,
'TRAP_HTTP_EXCEPTIONS': False,
'EXPLAIN_TEMPLATE_LOADING': False,
'PREFERRED_URL_SCHEME': 'http',
'JSON_AS_ASCII': True,
'JSON_SORT_KEYS': True,
'JSONIFY_PRETTYPRINT_REGULAR': True,
'JSONIFY_MIMETYPE': 'application/json',
'TEMPLATES_AUTO_RELOAD': None,
}
復制代碼

導入配置文件的幾種策略

app.config['DEBUG'] = True

PS: 由於Config對象本質上是字典,所以還可以使用app.config.update(...)

app.config.from_pyfile("python文件名稱")
如:
settings.py/
DEBUG = True

app.config.from_pyfile("settings.py")

app.config.from_envvar("環境變量名稱")

環境變量的值為python文件名稱名稱,內部調用from_pyfile方法

app.config.from_json("json文件名稱")

JSON文件名稱,必須是json格式,因為內部會執行json.loads

app.config.from_mapping({'DEBUG':True})

字典格式

app.config.from_object("python類或類的路徑")

復制代碼
app.config.from_object('pro_flask.settings.TestingConfig')

settings.py/

class Config(object):
DEBUG
= False
TESTING
= False
DATABASE_URI
= 'sqlite://:memory:'

class ProductionConfig(Config):
DATABASE_URI
= 'mysql://user@localhost/foo'

class DevelopmentConfig(Config):
DEBUG
= True

class TestingConfig(Config):
TESTING
= True

PS: 從sys.path中已經存在路徑開始寫

PS: settings.py文件默認路徑要放在程序root_path目錄,如果instance_relative_config為True,則就是instance_path目錄配置文件

復制代碼

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM