Pythonpython flask

flask之用户角色和用户资料编辑

2017-01-08  本文已影响481人  happyte

效果图

这一章节完成后的效果如下:

Github链接

https://github.com/happyte/flask-blog, 里面上传了个人博客系统的代码。

用户角色

class Role(db.Model):
    __tablename__ = 'roles'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String, nullable=True, unique=True)
    default = db.Column(db.Boolean, default=False)     
    permissions = db.Column(db.Integer)                 
    users = db.relationship('User', backref='itsrole')                 

只有普通用户的default字段为True,其它都默认为False。permissions字段是个整数,表示位操作,各操作都对应一个位位置,如果能执行某项操作的角色,其位被设为1。permissions各个权限位的表示如下:

角色 权限 说明
匿名 0b00000000(0x00) 未登陆的用户,只有阅读权限
普通用户 0b00000111(0x07) 发布文章、发表评论、关注其它用户
协管员 0b00001111(0x0f) 增加审查不当评论的权限
管理员 0b11111111(0xff) 拥有所有权限
@staticmethod
    def insert_roles():
        roles = {
            'User':(Permission.FOLLOW|Permission.COMMENT|
                     Permission.WRITE_ARTICLES, True),     # 只有普通用户的default为True
            'Moderare':(Permission.FOLLOW|Permission.COMMENT|
                    Permission.WRITE_ARTICLES|Permission.MODERATE_COMMENTS, False),
            'Administrator':(0xff, False)
        }
        for r in roles:
            role = Role.query.filter_by(name=r).first()
            if role is None:
                role = Role(name=r)
            role.permissions = roles[r][0]
            role.default = roles[r][1]
            db.session.add(role)
        db.session.commit()
(vent)$ python manage.py shell
>>>Role.insert_roles()
>>>Role.query.all()   # 查看所有角色

赋予角色

def __init__(self, **kwargs):
        super(User, self).__init__(**kwargs)        # 初始化父类
        if self.itsrole is None:
            if self.email == current_app.config['FLASK_ADMIN']:                  # 邮箱与管理者邮箱相同
                self.itsrole = Role.query.filter_by(permissions=0xff).first()    # 权限为管理者
            else:
                self.itsrole =  Role.query.filter_by(default=True).first()       # 默认用户

在构造函数中先初始化父类的构造函数,带上参数**kwargs。如果用户邮箱匹配坏境变量中的FLASK_ADMIN,该用户为管理员。

角色验证

from flask_login import UserMixin, AnonymousUserMixin
class User(UserMixin, db.Model):
    def can(self, permissions):          # 检查用户的权限
        return self.itsrole is not None and \
               (self.itsrole.permissions & permissions) == permissions

    def is_administrator(self):         # 检查是否为管理者
        return self.can(Permission.ADMINISTRATOR)
class AnonymousUser(AnonymousUserMixin):   # 匿名用户
    def can(self, permissions):
        return False

    def is_administrator(self):
        return False
login_manager.anonymous_user = AnonymousUser   # 将其设为用户未登陆时的current_user的值

视图函数对特定的用户开放

from functools import wraps
from flask import abort
from flask_login import current_user
from .models import Permission
# 装饰器函数,带参数,3层函数
def permission_required(permissions):
    def decorator(f):
        @wraps(f)
        def wrapper(*args, **kwargs):
            if not current_user.can(permissions):
                abort(403)
            return f(*args, **kwargs)
        return wrapper
    return decorator
# 调用上面装饰器函数
def admin_required(f):
    return permission_required(Permission.ADMINISTRATOR)(f)     # 带参数,且传递函数
from flask_login import login_required, current_user
from ..decorators import admin_required, permission_required
@main.route('/admin')      # 在登陆状态下只允许管理者进入,否则来到403禁止登陆界面
@login_required
@admin_required
def for_admin_only():
    return u'管理者进入'
@main.route('/moderator')
@login_required
@permission_required(Permission.MODERATE_COMMENTS)
def for_moderator_only():
    return u'协管员进入'

用户资料信息

from . import db
class User(UserMixin, db.Model):
    name = db.Column(db.String(64))         # 用户信息中的昵称
    location = db.Column(db.String(64))     # 用户地址
    about_me = db.Column(db.Text())         # 用户介绍
    member_since = db.Column(db.DATETIME(),        default=datetime.utcnow)    # 注册时间,datetime.utcnow不用带上括号
    last_seen = db.Column(db.DATETIME(), default=datetime.utcnow)       # 上次访问时间

新添加的字段包括昵称、地址、关于我、注册时间和上次访问时间。两个与时间相关的字段的默认值为都为datetime.utcnow,后面不需要带(),default接受函数作为默认值。上次访问时间是每次都需要刷新的,在before_app_request每次在请求前执行该函数,可以刷新上次访问时间。

class User(UserMixin, db.Model):

    def ping(self):
        self.last_seen = datetime.utcnow()         # 刷新上次访问时间
        db.session.add(self)
        db.session.commit()
@auth.before_app_request          # 用户已登陆、用户帐号还未确认、请求的的端点不在auth认证蓝本中
def before_request():
    if current_user.is_authenticated:
        current_user.ping()              # 在每次请求前刷新上次访问时间
        if not current_user.confirmed \
            and request.endpoint[:5] != 'auth.':
            return redirect(url_for('auth.unconfirmed'))

用户资料页面

@main.route('/user/<username>')
def user(username):
    user = User.query.filter_by(username=username).first()
    if user is None:
        abort(404)
    return render_template('user.html', user=user)

模板user.html的编写可以到文章最底端的github链接中去查看。

# 普通用户登陆表单
class EditProfileForm(FlaskForm):
   name = StringField(label=u'真实姓名', validators=[Length(0,64)])
   location = StringField(label=u'地址', validators=[Length(0,64)])
   about_me = TextAreaField(label=u'关于我')
   submit = SubmitField(label=u'提交')
# 管理员登陆表单,能编辑用户的电子邮件,用户名,确认状态和角色
class EditProfileAdministratorForm(FlaskForm):
  email = StringField(label=u'邮箱', validators=[DataRequired(), Length(1,64), Email()])
  username = StringField(label=u'用户名', validators=[DataRequired(), Length(1, 64)])
  confirmed = BooleanField(label=u'确认')
  role = SelectField(label=u'角色', coerce=int)

  name = StringField(label=u'真实姓名', validators=[Length(0, 64)])
  location = StringField(label=u'地址', validators=[Length(0, 64)])
  about_me = TextAreaField(label=u'关于我')
  submit = SubmitField(label=u'提交')

  # 初始化时要对role的复选框进行搭建
  def __init__(self, user, *args, **kwargs):
      super(EditProfileAdministratorForm, self).__init__(*args, **kwargs)
      self.role.choices = [(role.id, role.name) for role in Role.query.order_by(Role.name)]
      self.user = user
# 普通用户级别的编辑
@main.route('/edit-profile',methods=['GET','POST'])
@login_required
def edit_profile():
    form = EditProfileForm()
    if form.validate_on_submit():
        current_user.name = form.name.data
        current_user.location = form.location.data
        current_user.about_me = form.about_me.data
        flash(u'你的个人信息已经被更改')
        db.session.add(current_user)              # 更新个人资料
        db.session.commit()
        return redirect(url_for('main.user', username=current_user.username))
    form.name.data = current_user.name
    form.location.data = current_user.location
    form.about_me.data = current_user.about_me
    return render_template('edit_profile.html',form=form)
# 管理员级别的编辑
@main.route('/edit-profile/<int:id>',methods=['GET','POST'])
@login_required
@admin_required
def edit_profile_admin(id):
    user = User.query.get_or_404(id)  # 查找这个用户
    form = EditProfileAdministratorForm(user=user)
    if form.validate_on_submit():
        user.email = form.email.data
        user.username = form.username.data
        user.confirmed = form.confirmed.data
        user.itsrole = Role.query.get(form.role.data)
        user.name = form.name.data
        user.location = form.location.data
        user.about_me = form.about_me.data
        db.session.add(user)
        db.session.commit()
        flash(u'该用户的信息已经更新了')
        return redirect(url_for('main.user',username=user.username))
    form.email.data = user.email
    form.username.data = user.username
    form.confirmed.data = user.confirmed
    form.role.data = user.role_id          # role_id 与 itsrole是关联的
    form.name.data = user.name
    form.location.data = user.location
    form.about_me.data = user.about_me
    return render_template('edit_profile.html',form=form,user=user)
{% if user == current_user %}
               <a class="btn btn-default" href="{{ url_for('main.edit_profile') }}">
                   编辑信息
               </a>
               {% endif %}
上一篇下一篇

猜你喜欢

热点阅读