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 来生成相关报表。