flask 相對於不少國企的 oracle 數據庫而言,是比較新的,所以不少古老的設計並不必定適合較新的 flask 的標準,但做爲後來者,你得向前兼容,你得適應需求。
本章內容就來解釋一下上一章—— 基於 oracle 的 flask 項目(一)——配置項目留下的彩蛋——數據庫到底留下了什麼樣的坑?
絕對大多數的網站須要管理功能的,這個功能是不對外開放,須要有權限的用戶登陸後才能操做的。這個登陸功能對於大牛來講,確定是操做 session, cookies 了,其實沒必要這麼麻煩, flask-login 插件能夠解決你的登陸問題,可是要注意一些小細節,本章內容就是來討論一些細節內容。css
使用數據庫及映射類的時候,須要用到 sqlalchemy 第三方庫, flask 也提供了一個封裝好的插件 flask-sqlalchemy ,拿來使用便可。可是要使用 sqlalchemy, 在建立映射類的時候,必須得設置主鍵。可是不少前輩的 DBA 們的眼裏但是沒有 flask 的概念的,不少表是沒有設置主鍵的,咱們該怎麼辦?html
答:先對 DBA 管理員翻個白眼,而後本身默默的作事吧。還能怎麼辦呢!!!
找個具備惟一性,不重複的字段,在建立映射類的時候,把該字段定義爲主鍵。也就是說,無論數據庫中是否認義了主鍵,只要映射類種定義了便可。
固然,有的同窗會說,咱們找不到具備惟一性,不重複的字段,該怎麼辦?那就繼續給你的 DBA 管理員翻白眼唄,翻到他清醒爲止。git
還好,個人項目中的數據庫仍是有主鍵的,無需在映射類種,創建虛假的主鍵。程序員
內容不在贅述,請參加代碼。github
在 app/__init__.py
裏進行設置:web
login_manager = LoginManager() login_manager.session_protection = 'strong' # 能夠設置None,'basic','strong' 以提供不一樣的安全等級,通常設置strong,若是發現異常會登出用戶。 login_manager.login_view = 'show.login' # 這裏填寫你的登錄界面的路由 def create_app(config_name): """ 使用工廠函數初始化程序實例""" .... login_manager.init_app(app=app)
不少時候,咱們會遇到 remember_me 無效的狀況,請將 login_manager.session_protection
設置成 basic 試試。sql
詳細設置請看程序註釋及[源代碼02]()。數據庫
讓 models.py
中的用戶映射類繼承 flask_login 中的 UserMixin 類,該類實現了 4 個用戶方法,基本上可以知足用戶登陸的需求,如需其它的用戶方法,可自行定義。flask
class OusiStaff(UserMixin, db.Model): __tablename__ = 'ousi_staff' sid = db.Column(db.Integer, primary_key=True) department = db.Column(db.String(8)) name = db.Column(db.String(8)) password = db.Column(db.String(8)) phone = db.Column(db.String(11)) role = db.Column(db.String(8)) def is_admin(self): # 自行定義的方法,用於權限判斷 return self.role == 'admin' class AnonymousUser(AnonymousUserMixin): ''' 繼承至該類的用戶模型 將做爲未登錄時的用戶模型,能夠保持代碼的一致性。 ''' def is_admin(self): # 自行定義的方法,用於權限判斷 return False login_manager.anonymous_user = AnonymousUser
也是在 models.py
裏實現:安全
@login_manager.user_loader def load_user(user_id): return OusiStaff.query.get(int(user_id))
此處,不詳細講解,僅僅是實現了一個回調用戶的函數。
既然使用了登陸功能,那麼確定是有些內容不能讓未登陸的用戶觀看,這就須要在試圖函數定義的時候加上一個 login_required 裝飾器了。
這個功能的實現很簡單,在 views.py
裏進行修改:
... from flask_login import login_required, login_user, logout_user ... @show.route('/', methods = ['GET', 'POST']) @show.route('/index', methods = ['GET', 'POST']) @login_required def index(): return render_template('show/index.html')
至此,你能夠測試本身的項目了。
NotImplementedError: No 'id' attribute - override 'get_id'
錯誤的問題
...
bug 如影隨從。這是你遇到的第一個錯誤。你會發現登陸以後立刻就報這個錯誤。那麼兵來將擋水來土掩,找到問題,解決問題。
首先,報錯的地點顯示是咱們本身的代碼中的 login_user
,而真正報錯的地點是 minins.py
源碼中的 39 行,那麼這一行的真面目是什麼呢?
def get_id(self): try: return text_type(self.id) except AttributeError: raise NotImplementedError('No `id` attribute - override `get_id`')
你能夠清晰的看到,這個 get_id
函數的返回值是 return text_type(self.id)
是當前用戶的 id。那麼咱們的 models.py
中定義的 OusiStaff
類有 id 這個字段嗎?沒有。只有一個做爲主鍵的 sid 字段。看到這裏,估計你會對之前的 DBA 管理員問候不少聲了,OK,稍安勿躁,問候了以後還得解決問題。很直觀的解決方法是,修改源碼,將 return text_type(self.id)
修改成 return text_type(self.sid)
。可是這樣的方法很危險,很形成一些其它項目的兼容性問題。顯得這個程序員很 low。
再次咱們用一種更好、更優雅的方法來解決。在 models.py
文件內的 OusiStaff
映射類中添加以下內容:
class OusiStaff(UserMixin, db.Model): ... ... @property def id(self): return self.sid
增長一個 id 屬性。解決問題。
神奇的 @property。 彩蛋就如此簡單的被解決。
打開頁面,顯示正常。
下節更精彩,咱們將講解使用 flask-sqlalchemy 來生成相關報表。