zoukankan      html  css  js  c++  java
  • BBS网站的制作

     源码地址:https://github.com/FFlask/easy_bbs.git

    1、需求分析

    目的是做一个类似于贴吧的BBS论坛,做出单个贴吧的基本功能。

    对于用户,具有登陆,注册,看帖发帖,评论,签到,点赞,点踩,关注,发私信,群聊功能,个人主页

    对于管理员,具有帖子的删改、置顶、加精,评论的删改。普通的用户的权限修改,增删改查。

    2、数据库设计

    2.1 数据表关系图

     

    2.2 数据表设计

    用户表

     用户关系表(关注表)

     

     角色权限表

     签到表

     帖子表

     评论表

     赞踩表

     

     巨幕图表

    聊天记录表

    私信表

    3、框架选择

    由于最近在学习Flask框架,本项目采用Flask框架和其配套模块

    前端使用Bootstrap框架

    4、具体功能实现

    4.1 普通用户(正常使用)

    4.1.1 注册

     

      1 注册的功能主要就是向User表中新增数据
      2 主要相关模块werkzeug.security密码的加密和验证
      3 FlaskForm用于表单的验证
      4 
      5 
      6 #构建模型
      7 --bbs/models.py--
      8 #用户表
      9 class User(UserMixin,db.Model):
     10     __tablename__ = 'user'
     11     id = db.Column(db.Integer,primary_key=True,index=True)
     12     email = db.Column(db.String(64),unique=True,index=True)
     13     username = db.Column(db.String(64),unique=True,index=True)
     14     password_hash = db.Column(db.String(128))
     15     #创建时间自动添加
     16     create_time = db.Column(db.DateTime,default=datetime.datetime.utcnow)
     17     last_seen = db.Column(db.DateTime)
     18     description = db.Column(db.TEXT)
     19     head_img = db.Column(db.TEXT,default='111.jpg')
     20     role_id = db.Column(db.Integer,db.ForeignKey('role.id'))
     21 
     22     
     23     #新增用户默认是普通用户权限
     24     def __init__(self,*args,**kwargs):
     25         super(User,self).__init__(*args,**kwargs)
     26         if self.role is None:
     27             if self.username == 'admin':
     28                 self.role = Role.query.filter_by(role_name='Admin').first()
     29             else:
     30                 self.role = Role.query.filter_by(role_name='User').first()
     31     
     32     #验证密码时使用password,存储时使用password_hash,保障其安全性
     33     @property
     34     def password(self):
     35         raise AttributeError('密码不可读')
     36 
     37     @password.setter
     38     def password(self,password):
     39         self.password_hash = generate_password_hash(password)
     40 
     41     def verify_password(self,password):
     42         return check_password_hash(self.password_hash,password)
     43         
     44 
     45     def __repr__(self):
     46         return '<User %r---%r>'%(self.email,self.username)
     47         
     48         
     49 #表单类    
     50 --bbs/bbs1/forms.py--    
     51 class RegisterForm(FlaskForm):
     52     email = StringField('邮箱:',validators=[DataRequired(),Length(1,64),Email()])
     53     username = StringField('用户名:',validators=[DataRequired(),Length(1,64)])
     54     password = PasswordField('密码:',validators=[DataRequired(),EqualTo('password2','密码输入不一致')])
     55     password2 = PasswordField('重复密码:',validators=[DataRequired()])
     56     submmit = SubmitField('注册')
     57     
     58     #validate_+字段,在表单输入检测出问题时自动调用
     59     def validate_email(self,field):
     60         if User.query.filter_by(email = field.data).first():
     61             raise ValidationError('邮箱已注册')
     62 
     63     def validate_username(self,field):
     64         if User.query.filter_by(username = field.data).first():
     65             raise ValidationError('用户名已注册')        
     66         
     67         
     68 #业务逻辑,用户表中添加一条数据        
     69 --bbs/bbs1/views.py--
     70 @bbs1.route('/register',methods=['GET','POST'])
     71 def register():
     72     register_form = RegisterForm()
     73     if register_form.validate_on_submit():
     74         user = User(
     75             email = register_form.email.data,
     76             username = register_form.username.data,
     77             password = register_form.password.data
     78         )
     79         db.session.add(user)
     80         db.session.commit()
     81         return redirect(url_for('bbs1.login'))
     82     return render_template('register.html',register_form=register_form)
     83     
     84 
     85 #前端页面
     86 --register.html--    
     87 {% extends 'base.html' %}
     88 {% block title %} 注册 {% endblock %}
     89 {% block contnet %}
     90 <h2>注册新用户</h2>
     91 {% from '_filed.html' import render_field %}
     92 <form method="POST" action="{{ url_for('bbs1.edit_post') }}" >
     93     {#   不要忘记csrf_token#}
     94   {{ register_form.hidden_tag() }}
     95   <table>
     96     {{ render_field(register_form.username) }}
     97     {{ render_field(register_form.email) }}
     98     {{ render_field(register_form.password) }}
     99     {{ render_field(register_form.password2) }}
    100   </table>
    101   {{ register_form.submmit() }}
    102 </form>
    103 {% endblock %}
    View Code

    4.1.2 登陆

     

      1 登陆包括登陆和登陆后的权限控制
      2 主要相关模块flask_login,用于用户的登陆和权限管理
      3 
      4 
      5 #flask_login的设置
      6 --bbs/__init__.py
      7 login_manager = LoginManager()
      8 #设置验证强度,主要影响cookice过期时间
      9 login_manager.session_protection = 'strong'
     10 #设置登陆失败后的跳转
     11 login_manager.login_view = 'bbs1.login'
     12 
     13 #构建模型
     14 --bbs/models.py--
     15 #使用flask_login的必须步骤,用于用户的载入
     16 @login_manager.user_loader
     17 def load_user(user_id):
     18     return User.query.get(int(user_id))
     19     
     20 #用户表,使用flask_login的必须步骤,需要继承flask_login.UserMixin
     21 class User(UserMixin,db.Model):
     22     password_hash = db.Column(db.String(128))
     23     role_id = db.Column(db.Integer,db.ForeignKey('role.id'))
     24 
     25     #新增用户默认是普通用户权限
     26     def __init__(self,*args,**kwargs):
     27         super(User,self).__init__(*args,**kwargs)
     28         if self.role is None:
     29             if self.username == 'admin':
     30                 self.role = Role.query.filter_by(role_name='Admin').first()
     31             else:
     32                 self.role = Role.query.filter_by(role_name='User').first()
     33                 
     34     #验证密码时使用password,存储时使用password_hash,保障其安全性
     35     @property
     36     def password(self):
     37         raise AttributeError('密码不可读')
     38 
     39     @password.setter
     40     def password(self,password):
     41         self.password_hash = generate_password_hash(password)
     42 
     43     def verify_password(self,password):
     44         return check_password_hash(self.password_hash,password)
     45         
     46     def update_last_seen(self):
     47         self.last_seen = datetime.datetime.utcnow()
     48         db.session.add(self)
     49         db.session.commit()
     50         
     51     #验证用户是否包含某权限,使用与操作,始终返回两者中较小的值
     52     def can(self,permissions):
     53         return self.role is not None and (self.role.permissions & permissions) == permissions
     54 
     55     def is_admin(self):
     56         return self.can(Permissions.Admin)
     57 
     58     def is_manager(self):
     59         return self.can(Permissions.Manager)
     60 
     61     def __repr__(self):
     62         return '<User %r---%r>'%(self.email,self.username)
     63 
     64                 
     65 #权限类,使用十六进制数字表示不同的权限
     66 class Permissions:
     67     Visit = 0x01
     68     Read = 0x02
     69     Write = 0x04
     70     Manager = 0x08
     71     Admin = 0xFF                
     72                 
     73 #角色权限表
     74 class Role(db.Model):
     75     __tablename__ = 'role'
     76     id = db.Column(db.Integer,primary_key=True,index=True)
     77     role_name = db.Column(db.String(64),unique=True,index=True)
     78     permissions = db.Column(db.Integer)
     79     user = db.relationship('User',backref='role')
     80     
     81     #给不同的角色分配一定的权限,分为游客(Visitor),普通用户(User),管理员(Manager),最高管理员(Admin)
     82     #这里需要在with app.app_context()中执行一下,用来建立角色并分配权限
     83     @staticmethod
     84     def init_role():
     85         roles = {
     86             'Visitor':Permissions.Visit,
     87             'User':Permissions.Visit|Permissions.Read|Permissions.Write,
     88             'Manager':Permissions.Visit|Permissions.Read|Permissions.Write|Permissions.Manager,
     89             'Admin':Permissions.Admin
     90         }
     91         for role_name,role_permissions in roles.items():
     92             role = Role(role_name=role_name,permissions=role_permissions)
     93             db.session.add(role)
     94             db.session.commit()
     95 
     96     def __repr__(self):
     97         return '<Role %r>'%(self.role_name)
     98         
     99 
    100 #业务逻辑,验证用户名密码通过,登陆用户
    101 --bbs/bbs1/views.py--
    102 @bbs1.route('/login',methods=['GET','POST'])
    103 def login():
    104     login_form = LoginForm()
    105     if login_form.validate_on_submit():
    106         user = User.query.filter_by(
    107             username = login_form.username.data,
    108             email = login_form.email.data
    109         ).first()
    110         if user and user.verify_password(login_form.password.data):
    111             login_user(user)
    112             #登陆后刷新最后登录时间
    113             user.update_last_seen()
    114             return redirect(request.args.get('next') or url_for('bbs1.index'))
    115         else:
    116             flash('用户名或密码错误')
    117     return render_template('login.html',login_form=login_form)
    118 
    119 #登出用户,需要@login_required,必须在登陆状态才能登陆
    120 @bbs1.route('/logout')
    121 @login_required
    122 def logout():
    123     logout_user()
    124     return redirect(url_for('bbs1.index'))
    125     
    126     
    127 #权限验证装饰器
    128 --bbs/bbs1/decorators.py--
    129 from functools import wraps
    130 #current_user表示当前登陆用户
    131 from flask_login import current_user
    132 
    133 #如果当前用户不具有某权限,则返回403
    134 def permission_required(permission):
    135     def decorator(func):
    136         @wraps(func)
    137         def decorated_function(*args, **kwargs):
    138             if not current_user.can(permission):
    139                 abort(403)
    140             return func(*args, **kwargs)
    141         return decorated_function
    142     return decorator
    143 
    144 def is_manager(func):
    145     return permission_required(Permissions.Manager)(func)
    146 
    147 def is_admin(func):
    148     return permission_required(Permissions.Admin)(func)
    149     
    150     
    151 #登陆表单
    152 --bbs/bbs1/forms.py
    153 class LoginForm(FlaskForm):
    154     email = StringField('邮箱:', validators=[DataRequired(), Length(1, 64), Email()])
    155     username = StringField('用户名:', validators=[DataRequired(), Length(1, 64)])
    156     password = PasswordField('密码:', validators=[DataRequired()])
    157     submmit = SubmitField('登录')
    158     
    159 #前端页面
    160 --login.html--
    161 {% extends 'base.html' %}
    162 {% block title %} 登陆 {% endblock %}
    163 {% block contnet %}
    164 <h2>登陆</h2>
    165 {% from '_filed.html' import render_field %}
    166 <form method="POST" action="{{ url_for('bbs1.login') }}">
    167   {{ login_form.hidden_tag() }}
    168   <table>
    169     {{ render_field(login_form.username) }}
    170     {{ render_field(login_form.email) }}
    171     {{ render_field(login_form.password) }}
    172   </table>
    173   {{ login_form.submmit() }}
    174 </form>
    175 {#    显示后端闪现内容,这里就是用户名密码错误的信息#}
    176     {% for msg in get_flashed_messages()  %}
    177         <p>{{ msg }}</p>
    178 {% endfor %}
    179 {% endblock %}
    View Code

    4.1.3 看帖发帖

     

      1 发帖的功能主要就是向Post表中新增数据
      2 看帖的功能主要就是查看Post表中的数据
      3 重点是分页展示
      4 
      5 
      6 
      7 #构建模型
      8 --bbs/models.py--
      9 #帖子表
     10 class Post(db.Model):
     11     __tablename__ = 'post'
     12     id = db.Column(db.Integer,primary_key=True,index=True)
     13     user_id = db.Column(db.Integer,db.ForeignKey('user.id'))
     14     title = db.Column(db.String(128),unique=True,index=True)
     15     body = db.Column(db.Text)
     16     create_time = db.Column(db.DateTime,default=datetime.datetime.utcnow)
     17     last_modify_time = db.Column(db.DateTime)
     18     #默认可读
     19     can_seen = db.Column(db.Boolean,default= True)
     20     #默认不加精
     21     is_best = db.Column(db.Boolean,default= False)
     22     #默认不置顶
     23     is_top = db.Column(db.Boolean,default= False)
     24     comment = db.relationship('Comment',backref='post')
     25     zancai = db.relationship('ZanCai',backref='post')
     26 
     27     def __repr__(self):
     28         return '<Post %r>'%self.title
     29         
     30 #表单类    
     31 --bbs/bbs1/forms.py--    
     32 class EditPostForm(FlaskForm):
     33     title = StringField('标题:',validators=[DataRequired()])
     34     body = TextAreaField('帖子内容:',validators=[DataRequired()])
     35     submmit = SubmitField('提交')
     36     
     37 #业务逻辑
     38 --bbs/bbs1/views.py--
     39 #发帖
     40 @bbs1.route('/edit_post',methods=['GET','POST'])
     41 @login_required
     42 def edit_post():
     43     edit_post_form = EditPostForm()
     44     if edit_post_form.validate_on_submit():
     45         post = Post(
     46             user = current_user,
     47             title=edit_post_form.title.data,
     48             body=edit_post_form.body.data
     49         )
     50         db.session.add(post)
     51         db.session.commit()
     52         return redirect(url_for('bbs1.post'))
     53     return render_template('edit_post.html',edit_post_form=edit_post_form)
     54 
     55 #看贴,分页后展示
     56 @bbs1.route('/post')
     57 def post():
     58     page = request.args.get('page', 1, type=int)
     59     pagination = Post.query.order_by(Post.id.desc()).paginate(page, per_page=10, error_out=False)
     60     posts = pagination.items
     61     return render_template('post.html',posts = posts,pagination=pagination)
     62     
     63 
     64 #前端页面
     65 #发帖
     66 --edit_post.html--
     67 {% extends 'base.html' %}
     68 {% block title %} 发帖 {% endblock %}
     69 {% block contnet %}
     70     <div class="jumbotron">
     71   <h2>发帖</h2>
     72   {% from '_filed.html' import render_field %}
     73 <form method="POST" action="{{ url_for('bbs1.edit_post') }}">
     74   {{ edit_post_form.hidden_tag() }}
     75   <table>
     76     {{ render_field(edit_post_form.title) }}
     77     {{ render_field(edit_post_form.body) }}
     78   </table>
     79   {{ edit_post_form.submmit() }}
     80 </form>
     81 </div>
     82 
     83 {% endblock %}
     84 
     85 #看帖
     86 --post.html--
     87 {% extends 'base.html' %}
     88 {% block title %} 帖子 {% endblock %}
     89 {% block contnet %}
     90 
     91     {% for post in posts %}
     92         {% if post.can_seen %}
     93 
     94         <div class="media">
     95       <div class="media-body">
     96         <h4 class="media-heading"><a href="#"><span class="glyphicon glyphicon-flag"></span>{{ post.title }}</a></h4>
     97         <h5><a href="#">{{ post.body }}</a></h5>
     98 
     99       </div>
    100             <div class="media-right">
    101             <a href="#">
    102           <img class="media-object" src="/static/uploads/{{ post.user.head_img }}" alt="11111">
    103         </a>
    104       </div>
    105               <div class="media-bottom">
    106           <div class="btn-group" role="group">
    107       <button type="button" class="btn btn-default" id="post_zan{{ post.id }}" onclick="dian_post_zan({{ post.id }})"><a href="#"><span class="glyphicon glyphicon-thumbs-up"></span>赞({{ post.zancai | length }})</a></button>
    108       <button type="button" class="btn btn-default"><a href="{{ url_for('bbs1.comment',post_id=post.id) }}"><span class="glyphicon glyphicon-pencil"></span>评论({{ post.comment | length }} )</a></button>
    109        <button type="button" class="btn btn-default"><a href="{{ url_for('bbs1.userprofile',username=post.user.username) }}"><span class="glyphicon glyphicon-user"></span>{{ post.user.username }}</a></button>
    110        <button type="button" class="btn btn-default"><a href="#"><span class="glyphicon glyphicon-time"></span>{{ post.create_time }}</a></button>
    111         </div>
    112 
    113       </div>
    114     </div>
    115     <hr>
    116         {% endif %}
    117     {% endfor %}
    118 {#    页码展示#}
    119         《-{% for p in pagination.iter_pages() %}
    120         <a href="{{ url_for('bbs1.post',page= p) }}">{{ p }}</a>
    121     {% endfor %}-122 {% endblock %}
    View Code

    4.1.4 评论

     

      1 发帖的功能主要就是向Post表中新增数据
      2 看帖的功能主要就是查看Post表中的数据
      3 重点是分页展示
      4 
      5 
      6 
      7 #构建模型
      8 --bbs/models.py--
      9 #帖子表
     10 class Post(db.Model):
     11     __tablename__ = 'post'
     12     id = db.Column(db.Integer,primary_key=True,index=True)
     13     user_id = db.Column(db.Integer,db.ForeignKey('user.id'))
     14     title = db.Column(db.String(128),unique=True,index=True)
     15     body = db.Column(db.Text)
     16     create_time = db.Column(db.DateTime,default=datetime.datetime.utcnow)
     17     last_modify_time = db.Column(db.DateTime)
     18     #默认可读
     19     can_seen = db.Column(db.Boolean,default= True)
     20     #默认不加精
     21     is_best = db.Column(db.Boolean,default= False)
     22     #默认不置顶
     23     is_top = db.Column(db.Boolean,default= False)
     24     comment = db.relationship('Comment',backref='post')
     25     zancai = db.relationship('ZanCai',backref='post')
     26 
     27     def __repr__(self):
     28         return '<Post %r>'%self.title
     29         
     30 #表单类    
     31 --bbs/bbs1/forms.py--    
     32 class EditPostForm(FlaskForm):
     33     title = StringField('标题:',validators=[DataRequired()])
     34     body = TextAreaField('帖子内容:',validators=[DataRequired()])
     35     submmit = SubmitField('提交')
     36     
     37 #业务逻辑
     38 --bbs/bbs1/views.py--
     39 #发帖
     40 @bbs1.route('/edit_post',methods=['GET','POST'])
     41 @login_required
     42 def edit_post():
     43     edit_post_form = EditPostForm()
     44     if edit_post_form.validate_on_submit():
     45         post = Post(
     46             user = current_user,
     47             title=edit_post_form.title.data,
     48             body=edit_post_form.body.data
     49         )
     50         db.session.add(post)
     51         db.session.commit()
     52         return redirect(url_for('bbs1.post'))
     53     return render_template('edit_post.html',edit_post_form=edit_post_form)
     54 
     55 #看贴,分页后展示
     56 @bbs1.route('/post')
     57 def post():
     58     page = request.args.get('page', 1, type=int)
     59     pagination = Post.query.order_by(Post.id.desc()).paginate(page, per_page=10, error_out=False)
     60     posts = pagination.items
     61     return render_template('post.html',posts = posts,pagination=pagination)
     62     
     63 
     64 #前端页面
     65 #发帖
     66 --edit_post.html--
     67 {% extends 'base.html' %}
     68 {% block title %} 发帖 {% endblock %}
     69 {% block contnet %}
     70     <div class="jumbotron">
     71   <h2>发帖</h2>
     72   {% from '_filed.html' import render_field %}
     73 <form method="POST" action="{{ url_for('bbs1.edit_post') }}">
     74   {{ edit_post_form.hidden_tag() }}
     75   <table>
     76     {{ render_field(edit_post_form.title) }}
     77     {{ render_field(edit_post_form.body) }}
     78   </table>
     79   {{ edit_post_form.submmit() }}
     80 </form>
     81 </div>
     82 
     83 {% endblock %}
     84 
     85 #看帖
     86 --post.html--
     87 {% extends 'base.html' %}
     88 {% block title %} 帖子 {% endblock %}
     89 {% block contnet %}
     90 
     91     {% for post in posts %}
     92         {% if post.can_seen %}
     93 
     94         <div class="media">
     95       <div class="media-body">
     96         <h4 class="media-heading"><a href="#"><span class="glyphicon glyphicon-flag"></span>{{ post.title }}</a></h4>
     97         <h5><a href="#">{{ post.body }}</a></h5>
     98 
     99       </div>
    100             <div class="media-right">
    101             <a href="#">
    102           <img class="media-object" src="/static/uploads/{{ post.user.head_img }}" alt="11111">
    103         </a>
    104       </div>
    105               <div class="media-bottom">
    106           <div class="btn-group" role="group">
    107       <button type="button" class="btn btn-default" id="post_zan{{ post.id }}" onclick="dian_post_zan({{ post.id }})"><a href="#"><span class="glyphicon glyphicon-thumbs-up"></span>赞({{ post.zancai | length }})</a></button>
    108       <button type="button" class="btn btn-default"><a href="{{ url_for('bbs1.comment',post_id=post.id) }}"><span class="glyphicon glyphicon-pencil"></span>评论({{ post.comment | length }} )</a></button>
    109        <button type="button" class="btn btn-default"><a href="{{ url_for('bbs1.userprofile',username=post.user.username) }}"><span class="glyphicon glyphicon-user"></span>{{ post.user.username }}</a></button>
    110        <button type="button" class="btn btn-default"><a href="#"><span class="glyphicon glyphicon-time"></span>{{ post.create_time }}</a></button>
    111         </div>
    112 
    113       </div>
    114     </div>
    115     <hr>
    116         {% endif %}
    117     {% endfor %}
    118 {#    页码展示#}
    119         《-{% for p in pagination.iter_pages() %}
    120         <a href="{{ url_for('bbs1.post',page= p) }}">{{ p }}</a>
    121     {% endfor %}-122 {% endblock %}
    View Code

    4.1.5 签到

     如上图

     1 签到的功能主要就是向SignIn表中新增数据
     2 查看签到的功能主要就是判断是否签到和是否到时间能签到后查看SignIn表中的数据
     3 
     4 
     5 #构建模型
     6 --bbs/bbs1/models.py--
     7 #签到表
     8 class SignIn(db.Model):
     9     __tablename__ = 'signin'
    10     id = db.Column(db.Integer,primary_key=True,index=True)
    11     is_sign_in = db.Column(db.Boolean,default=True)
    12     create_time = db.Column(db.DateTime,default=datetime.datetime.utcnow)
    13     user_id = db.Column(db.Integer,db.ForeignKey('user.id'))
    14 
    15     def __repr__(self):
    16         return '<SignIn %r--%r>'%(User.query.filter_by(id=self.user_id).first(),self.create_time)
    17         
    18 
    19 #业务逻辑
    20 --bbs/bbs1/views.py--
    21 @bbs1.route('/signin/<username>',methods=['GET','POST'])
    22 @login_required
    23 def signin(username):
    24     user1 = User.query.filter_by(username=username).first()
    25     signin1 = SignIn.query.filter_by(user=user1).order_by(SignIn.create_time.desc()).first()
    26     day1 = datetime.timedelta(days=1)
    27 
    28     #打开页面时,使用ajax发送post请求来确定签到的状态
    29     #大于一天可以签到且之前签过到才可以继续签到,没签过到的之前跳过
    30     if request.method == 'POST' and signin1 and signin1.create_time - datetime.datetime.utcnow()>day1:
    31         is_sign_in = True
    32         return make_response(json.dumps({'status': is_sign_in}))
    33     elif request.method == 'POST' and signin1:
    34         is_sign_in = False
    35         sign_sum = SignIn.query.filter_by(user=user1).count()
    36         return make_response(json.dumps({'status': is_sign_in,'sign_sum':str(sign_sum)}))
    37 
    38     #get请求用来签到
    39     if signin1 is None:
    40         new_sign_in = SignIn(user=user1)
    41         db.session.add(new_sign_in)
    42         db.session.commit()
    43     if signin1 and signin1.create_time - datetime.datetime.utcnow()>day1:
    44         new_sign_in = SignIn(user=user1)
    45         db.session.add(new_sign_in)
    46         db.session.commit()
    47     return redirect(request.args.get('next') or url_for('bbs1.index'))
    48     
    49     
    50 前端页面,相关部分
    51 --base.html--
    52 <script>
    53 function end_load() {
    54 
    55         // 新建XMLHttpRequest对象
    56         var req = new XMLHttpRequest();
    57         var signin = document.getElementById('signin');
    58         // 状态发生变化时,函数被回调
    59         req.onreadystatechange=function () {
    60             //状态码为4代表请求完成
    61             if (req.readyState==4&&req.status==200) {
    62                 data = req.responseText;
    63                 data = JSON.parse(data);
    64                 if (data['status'] == false){
    65                     signin.innerText = "已签到("+data['sign_sum']+"天)";
    66                 }
    67             }
    68         };
    69         //post方式建立连接
    70         req.open('post','http://127.0.0.1:5000/signin/{{ current_user.username }}',true);
    71         //post请求的编码方式,这是浏览器的原生 form 表单的默认编码方式
    72         req.setRequestHeader("Content-type","application/x-www-form-urlencoded");
    73         //发送请求
    74         req.send('11');
    75         }
    76 </script>
    View Code

    4.1.6 点赞

     如上图

     1 点赞的功能主要是在ZanCai表中添加一条点赞记录
     2 一个帖子一个用户只能点赞一次,没有点赞的则赞+1
     3 
     4 
     5 
     6 #构建模型
     7 --bbs/bbs1/models.py--
     8 #点赞表
     9 #初期设计的时候是想一个表同时保存点赞和点踩的数据,后来感觉功能重复就只点赞了
    10 class ZanCai(db.Model):
    11     __tablename__='zancai'
    12     id = db.Column(db.Integer,primary_key=True,index=True)
    13     #True是post,False是comment
    14     post_or_comment = db.Column(db.Boolean)
    15     # True是zan,False是cai
    16     zan_or_cai = db.Column(db.Boolean)
    17     post_id = db.Column(db.Integer,db.ForeignKey('post.id'))
    18     comment_id = db.Column(db.Integer,db.ForeignKey('comment.id'))
    19     user_id = db.Column(db.Integer,db.ForeignKey('user.id'))
    20 
    21     def __repr__(self):
    22         return '<ZanCai %r--%r>'%(self.id,self.zan_or_cai)
    23         
    24 
    25 #业务逻辑
    26 #前端利用ajax发送点赞的数据
    27 --bbs/bbs1/views.py--
    28 @bbs1.route('/zancai',methods=['GET','POST'])
    29 @login_required
    30 def zancai():
    31     if request.method == 'POST':
    32         post_or_comment = request.form.get('post_or_comment')
    33         id = request.form.get('post_id')
    34         zan_or_cai = request.form.get('zan_or_cai')
    35         zancai2 = ZanCai.query.filter_by(
    36             user=current_user._get_current_object(),
    37             post_id=id,
    38             post_or_comment=bool(post_or_comment),
    39             zan_or_cai=bool(zan_or_cai)
    40         ).first()
    41         #已经点赞则返回已点赞
    42         if zancai2:
    43             message = {'state': 'fail'}
    44             return make_response(json.dumps(message))
    45         #没有点赞的则点赞
    46         else:
    47             zancai1 = ZanCai(
    48                 user = current_user._get_current_object(),
    49                 post_id = id,
    50                 post_or_comment= bool(post_or_comment),
    51                 zan_or_cai=bool(zan_or_cai)
    52                 )
    53             db.session.add(zancai1)
    54             db.session.commit()
    55             message = {'state': 'success'}
    56             return make_response(json.dumps(message))
    57             
    58             
    59 #前端页面
    60 #前端利用ajax发送点赞的数据,相关部分
    61 --post.html--
    62 <script>
    63     function dian_post_zan(post_id) {
    64         var edit_child_comment = document.getElementById('post_zan'+post_id);
    65         // 新建XMLHttpRequest对象
    66         var req = new XMLHttpRequest();
    67         // 状态发生变化时,函数被回调
    68         req.onreadystatechange=function () {
    69             //状态码为4代表请求完成
    70             if (req.readyState==4&&req.status==200) {
    71                 data = req.responseText;
    72                 data = JSON.parse(data);
    73                 location.reload();
    74             }
    75         };
    76         //post方式建立连接
    77         req.open('post','http://127.0.0.1:5000/zancai',true);
    78         //post请求的编码方式,这是浏览器的原生 form 表单的默认编码方式
    79         req.setRequestHeader("Content-type","application/x-www-form-urlencoded");
    80         //发送请求
    81         req.send("post_or_comment="+1+"&post_id="+post_id+"&zan_or_cai="+1);
    82     }
    83 </script>
    View Code

    4.1.7 关注

     

      1 点关注则关注,显示已关注,再点则取消关注
      2 实际点关注是在User2User表中添加数据,取消关注是在User2User表中删除数据
      3 
      4 #构建模型
      5 #角色关注表
      6 class User2User(db.Model):
      7     __tablename__ = 'user2user'
      8     #关注的id
      9     follower_id = db.Column(db.Integer,db.ForeignKey('user.id'),primary_key=True)
     10     #被关注的id
     11     followed_id = db.Column(db.Integer,db.ForeignKey('user.id'),primary_key=True)
     12     #关注的时间
     13     create_time = db.Column(db.DateTime,default=datetime.datetime.utcnow)
     14     
     15 #用户表
     16 #使用一些辅助方法来完成具体操作
     17 #这里是高级多对多,好处是可以获取关注表的关注时间
     18 class User(UserMixin,db.Model):
     19     __tablename__ = 'user'
     20     id = db.Column(db.Integer,primary_key=True,index=True)
     21     #cascade删除时删除所有关联项
     22     #高级多对多,需要指定foreign_keys = [User2User.follower_id],手工管理外键
     23     followed = db.relationship('User2User',foreign_keys = [User2User.follower_id],backref=db.backref('follower',lazy='joined'),
     24                                lazy='dynamic',cascade='all,delete-orphan')
     25     follower = db.relationship('User2User',foreign_keys = [User2User.followed_id],backref=db.backref('followed',lazy='joined'),
     26                                lazy='dynamic',cascade='all,delete-orphan')
     27     
     28     #关注
     29     def follow(self,user):
     30         if not self.is_following(user):
     31             u2u = User2User(follower_id=self.id,followed_id=user.id)
     32             db.session.add(u2u)
     33             db.session.commit()
     34     
     35     #取关
     36     def unfollow(self,user):
     37         u2u = User2User.query.filter_by(follower_id=self.id,followed_id=user.id).first()
     38         if u2u:
     39             db.session.delete(u2u)
     40             db.session.commit()
     41     
     42     #是否关注
     43     def is_following(self,user):
     44         return self.followed.filter_by(followed_id = user.id).first() is not None
     45     
     46     #是否被关注
     47     def is_followed_by(self,user):
     48         return self.follower.filter_by(follower_id = user.id).first() is not None
     49 
     50 
     51     def __repr__(self):
     52         return '<User %r---%r>'%(self.email,self.username)
     53         
     54 
     55         
     56 #业务逻辑
     57 #关注
     58 --bbs/bbs1/views.py--
     59 @bbs1.route('/user/<username>/follow')
     60 @login_required
     61 def follow(username):
     62     user1 = current_user._get_current_object()
     63     user2 = User.query.filter_by(username = username).first()
     64     if not user1.is_following(user2):
     65         print user1.is_following(user2)
     66         user1.follow(user2)
     67     return redirect(request.args.get('next') or url_for('bbs1.userprofile',username=username))
     68 
     69 #取关
     70 @bbs1.route('/user/<username>/unfollow')
     71 @login_required
     72 def unfollow(username):
     73     user1 = current_user._get_current_object()
     74     user2 = User.query.filter_by(username = username).first()
     75     if  user1.is_following(user2):
     76         user1.unfollow(user2)
     77     return redirect(request.args.get('next') or url_for('bbs1.userprofile',username=username))
     78     
     79 
     80 #前端页面
     81 --base_user.html--
     82 {% extends 'base.html' %}
     83 {% block contnet %}
     84 
     85     <h2><span class="glyphicon glyphicon-user"></span>{{ user1.username }}的主页</h2>
     86     <ul class="nav nav-tabs">
     87     {% if current_user.username==user1.username %}
     88   <li role="presentation" class="active"><a href="{{ url_for('bbs1.userprofile',username=current_user.username) }}">我的信息</a></li>
     89   <li role="presentation"><a href="{{ url_for('bbs1.user_post',username=current_user.username) }}">我的帖子</a></li>
     90   <li role="presentation"><a href="{{ url_for('bbs1.user_comment',username=current_user.username) }}">我的评论</a></li>
     91     <li role="presentation"><a href="{{ url_for('bbs1.user_followers',username=current_user.username) }}">我的关注</a></li>
     92     {% else %}
     93         <li role="presentation" class="active"> <a href="{{ url_for('bbs1.userprofile',username=user1.username) }}">{{ user1.username }}信息</a></li>
     94         <li role="presentation"> <a href="{{ url_for('bbs1.user_post',username=user1.username) }}">{{ user1.username }}帖子</a></li>
     95         <li role="presentation"><a href="{{ url_for('bbs1.user_comment',username=user1.username) }}">{{ user1.username }}评论</a></li>
     96         {#判断是否已关注#}
     97     {% if not current_user.is_following(user1) %}
     98         <li role="presentation"> <a href="{{ url_for('bbs1.follow',username = user1.username) }}">关注{{ user1.username }}</a></li>
     99         {% else %}
    100         <li role="presentation"> <a href="{{ url_for('bbs1.unfollow',username = user1.username) }}">取关{{ user1.username }}</a></li>
    101     {% endif %}
    102     {% endif %}
    103 </ul>
    104 
    105 
    106 {% endblock %}
    View Code

    4.1.8 群聊

     

      1 使用websocket协议实现聊天室的功能
      2 需要修改flask启动的默认web服务器,需要使用异步
      3 
      4 
      5 #修改flask启动的默认web服务器
      6 --bbs/manager.py--
      7 import sys
      8 reload(sys)
      9 sys.setdefaultencoding('utf-8')
     10 from bbs import db,create_app
     11 from  geventwebsocket.websocket import WebSocket,WebSocketError
     12 from  geventwebsocket.handler import WebSocketHandler
     13 from  gevent.pywsgi import WSGIServer
     14 
     15 app = create_app()
     16 
     17 if __name__ == '__main__':
     18     #manager.run()
     19     http_serve=WSGIServer(("0.0.0.0",5000),app,handler_class=WebSocketHandler)
     20     http_serve.serve_forever()
     21 
     22 
     23 #构建模型
     24 #这个不是必要的,只是为了记录聊天记录
     25 #这种还是用nosql记录更方便快捷
     26 class ChatLog(db.Model):
     27     __tablename__ = 'chat_log'
     28     id = db.Column(db.Integer,primary_key=True,index=True)
     29     user_id = db.Column(db.Integer,db.ForeignKey('user.id'))
     30     body = db.Column(db.TEXT)
     31     ip = db.Column(db.String(64))
     32     create_time = db.Column(db.DateTime,default=datetime.datetime.utcnow)
     33     
     34     #记录对方的Ip地址
     35     def __init__(self,*args,**kwargs):
     36         super(ChatLog,self).__init__(*args,**kwargs)
     37         self.ip = request.remote_addr
     38 
     39     def __repr__(self):
     40         return '<ChatLog %r--%r>'%(User.query.filter_by(id=self.user_id).first(),self.create_time)
     41         
     42 
     43 #业务逻辑
     44 #websocket接收聊天数据
     45 user_socket_dict={}
     46 @bbs1.route('/ws/<username>')
     47 def ws(username):
     48     user_socket=request.environ.get("wsgi.websocket")
     49     if not user_socket:
     50         return "请以WEBSOCKET方式连接"
     51 
     52     user_socket_dict[username]=user_socket
     53     print(user_socket_dict.get(username))
     54 
     55     while True:
     56         try:
     57             user_msg = user_socket.receive()
     58             #接收到数后,添加到聊天记录表
     59             if user_msg:
     60                 chat_log1 = ChatLog(body=user_msg,user=current_user._get_current_object())
     61                 db.session.add(chat_log1)
     62                 db.session.commit()
     63             #循环用户表,将接收到的信息广播给所有用户
     64             for user_name,u_socket in user_socket_dict.items():
     65 
     66                 who_send_msg={
     67                     "send_user":username,
     68                     "send_msg":user_msg
     69                 }
     70                 #接收到自己发给自己的数据则跳过此次循环
     71                 if user_socket == u_socket:
     72                     continue
     73                 u_socket.send(json.dumps(who_send_msg))
     74 
     75         except WebSocketError as e:
     76             user_socket_dict.pop(username)
     77             print('%s is leave'%(user_socket_dict))
     78 
     79 
     80 #前端页面,ajax实现
     81 --base.html--
     82 <script>
     83     var ws_url="ws://127.0.0.1:5000/ws/";
     84     var ws =null;
     85     #进入页面时连接websocket的后端
     86     function end_load() {
     87         var username = "{{ current_user.username }}";
     88         ws = new WebSocket(ws_url+username);
     89         ws.onmessage=function(serv_msg){
     90             msg=JSON.parse(serv_msg.data);
     91              //console.log(serv_msg.data);
     92             create_chart('y',msg)}
     93     }
     94     #接收到信息时添加到页面
     95     function create_chart(self,content) {
     96         if (self == "w"){
     97             self = "right";
     98             var spantag = document.createElement("span");
     99             spantag.innerText= content.send_msg;
    100             var spantag1 = document.createElement("span");
    101             spantag1.innerText=':我';
    102         }else{
    103             self = "left";
    104             var spantag = document.createElement("span");
    105             spantag.innerText=content.send_user+':';
    106 
    107             var spantag1 = document.createElement("span");
    108             spantag1.innerText=content.send_msg;
    109 
    110         }
    111         var divtag = document.createElement("div");
    112         divtag.style="text-align:"+self;
    113         divtag.appendChild(spantag);
    114         divtag.appendChild(spantag1);
    115         var char_window = document.getElementById('chat_window');
    116         char_window.appendChild(divtag);
    117 
    118     }
    119     document.getElementById("btn_send").addEventListener("click",function () {
    120 
    121         var send_msg=document.getElementById("send_msg");
    122         ws.send(send_msg.value);
    123 
    124         var s_msg = {send_msg:send_msg.value};
    125         create_chart('w',s_msg);
    126         send_msg.value='';
    127     })
    128 </script>
    View Code

    4.1.9 私信

     

    未实现 

     

    4.1.10 个人主页

     

      1 功能上相当于小型的后台管理,不过大部分数据都是只能看不能改
      2 可以管理个人信息、评论、帖子、关注、私信等
      3 
      4 
      5 #业务逻辑
      6 --bbs/bbs1/views.py--
      7 #个人信息查看
      8 @bbs1.route('/user/<username>/userprofile')
      9 def userprofile(username):
     10     user1 = User.query.filter_by(username=username).first()
     11     if user1==None:
     12         abort(404)
     13     return render_template('userprofile.html',user1=user1)
     14     
     15     
     16 #表单类,注意限制文件类型,否则就是上传漏洞
     17 class EditProfileForm(FlaskForm):
     18     description = TextAreaField('个人简介:',render_kw={'class':'form-control'})
     19     head_img = FileField('上传头像:',validators=[FileRequired(),
     20                                              FileAllowed(['jpg', 'png'], '只接收.jpg和.png格式的简历')],
     21                          render_kw={'class':'form-control'})
     22     submmit = SubmitField('提交',render_kw={'class':'btn btn-info'})
     23     
     24 
     25 #个人信息修改
     26 #这里主要是头像的上传,为了安全,将文件名改为当前时间加salt,再取md5值来保存
     27 @bbs1.route('/user/<username>/userprofile/user_edit_profile',methods=['GET','POST'])
     28 @login_required
     29 def user_edit_profile(username):
     30     edit_profile_profile = EditProfileForm()
     31     user1 = User.query.filter_by(username=username).first()
     32     if user1==None:
     33         abort(404)
     34     if edit_profile_profile.validate_on_submit() and current_user.username == user1.username:
     35         user1.description = edit_profile_profile.description.data
     36         # filename = edit_profile_profile.head_img.data.filename
     37         salt = 'salt11'
     38         m = hashlib.md5()
     39         m.update(str(datetime.datetime.now())+salt)
     40         filename = m.hexdigest()+'.jpg'
     41         basepath = os.path.dirname(__file__)
     42         upload_path = os.path.join(basepath.replace('\bbs1',''), 'static\uploads', filename)
     43         edit_profile_profile.head_img.data.save(upload_path)
     44         user1.head_img = filename
     45         db.session.add(user1)
     46         db.session.commit()
     47         return redirect(url_for('bbs1.userprofile',username=username))
     48     edit_profile_profile.head_img.data = user1.head_img
     49     edit_profile_profile.description.data = user1.description
     50     return render_template('user_edit_profile.html',user1=user1,edit_profile_profile=edit_profile_profile)
     51     
     52 #个人帖子
     53 @bbs1.route('/user/<username>/user_post')
     54 def user_post(username):
     55     user1 = User.query.filter_by(username=username).first()
     56     #post1 = Post.query.filter_by(user=user1).all()
     57     page = request.args.get('page', 1, type=int)
     58     pagination = Post.query.filter_by(user=user1).order_by(Post.id.asc()).paginate(page, per_page=5, error_out=False)
     59     post1= pagination.items
     60     return render_template('user_post.html',post1=post1,user1=user1,pagination=pagination)
     61     
     62 #个人评论
     63 @bbs1.route('/user/<username>/user_comment')
     64 def user_comment(username):
     65     user1 = User.query.filter_by(username=username).first()
     66     page = request.args.get('page', 1, type=int)
     67     pagination = Comment.query.filter_by(user=user1).order_by(Comment.id.asc()).paginate(page, per_page=5, error_out=False)
     68     user_comments= pagination.items
     69     return render_template('user_comment.html',user_comments =user_comments,user1=user1,pagination=pagination)
     70     
     71 #个人关注
     72 @bbs1.route('/user/<username>/user_followers')
     73 @login_required
     74 def user_followers(username):
     75     user1 = User.query.filter_by(username=username).first()
     76     followers = user1.followed.all()
     77     return render_template('user_followers.html',user1=user1,followers = followers)
     78     
     79     
     80 #前端页面比较简单且重复,就不展示了
     81 #有一点值得注意的,form要添加enctype="multipart/form-data"
     82 #另一点是多层集成模板的时候需要{{ super() }}
     83 --user_edit_profile.html--
     84 {% extends 'base_user.html' %}
     85 {% block title %} {{ user1.username }}的信息 {% endblock %}
     86 {% block contnet %}
     87 {{ super() }}
     88 
     89 <h3>修改用户信息</h3>
     90 {% from '_filed.html' import render_field %}
     91 {% if current_user.username == user1.username %}
     92 <form method="POST" action="{{ url_for('bbs1.user_edit_profile',username=current_user.username) }} " enctype="multipart/form-data">
     93   {{ edit_profile_profile.hidden_tag() }}
     94   <table class="table table-hover">
     95     {{ render_field(edit_profile_profile.head_img) }}
     96     {{ render_field(edit_profile_profile.description) }}
     97   </table>
     98   {{ edit_profile_profile.submmit() }}
     99 </form>
    100  {% endif %}
    101 {% endblock %}
    View Code

    4.2 管理员(后台管理)

    后台管理实际上就是数据库的增删改查的页面,业务逻辑比较少 

    4.2.1 首页管理

    首页巨幕图的添加、管理;明显水友的添加、管理;

     还没有完全实现

    4.2.2 帖子管理

    帖子的删改、置顶、加精、屏蔽

      1 帖子管理主要是帖子的排序查询、模糊查询,帖子的加精、置顶和屏蔽
      2 需要管理员权限
      3 
      4 #表单类
      5 --bbs/bbs_admin/forms.py--
      6 #查询
      7 class SearchManagerPostForm(FlaskForm):
      8     search = StringField(validators=[DataRequired()])
      9     kind = SelectField(choices=[
     10         ('id','ID'),('username','作者'),('title','标题'),('body','内容'),('create_time','创建时间'),
     11     ])
     12     submmit = SubmitField('查询')
     13 #编辑,少写了很多限制
     14 class EditManagerPostForm(FlaskForm):
     15     title = StringField()
     16     body = StringField()
     17     can_seen = BooleanField()
     18     is_best = BooleanField()
     19     is_top = BooleanField()
     20     submmit = SubmitField('提交')
     21     
     22     
     23 #业务逻辑
     24 --bbs/bbs_admin/views.py--
     25 #查询
     26 #使用get请求带参数传入排序选择
     27 #使用ajax传post请求来模糊查询指定项目
     28 @bbs_admin.route('/manager_post/<int:order_by_id>/<int:order_by_time>',methods=['GET','POST'])
     29 @login_required
     30 @is_manager
     31 def manager_post(order_by_id,order_by_time):
     32     if order_by_id==1 and order_by_time==0:
     33         page = request.args.get('page', 1, type=int)
     34         pagination = Post.query.order_by(Post.id.desc()).paginate(page, per_page=10, error_out=False)
     35         posts = pagination.items
     36     elif order_by_id==0 and order_by_time==1:
     37         page = request.args.get('page', 1, type=int)
     38         pagination = Post.query.order_by(Post.create_time.desc()).paginate(page, per_page=10, error_out=False)
     39         posts = pagination.items
     40     else:
     41         page = request.args.get('page', 1, type=int)
     42         pagination = Post.query.paginate(page, per_page=10, error_out=False)
     43         posts = pagination.items
     44     search_manager_post_form = SearchManagerPostForm()
     45     if search_manager_post_form.validate_on_submit():
     46         kind = search_manager_post_form.kind.data
     47         search_item = search_manager_post_form.search.data
     48         if kind=='username':
     49         #反射获取User.kind数据
     50             users_ = User.query.filter(getattr(User,kind).like(('%'+'%s'%search_item+'%'))).all()
     51             posts_ =[]
     52             for user in users_:
     53                 post1 = Post.query.filter_by(user = user).all()
     54                 for post2 in post1:
     55                     posts_.append(post2)
     56         else:
     57             page = request.args.get('page', 1, type=int)
     58             pagination = Post.query.filter(getattr(Post,kind).like(('%'+'%s'%search_item+'%'))).paginate(page, per_page=10, error_out=False)
     59             posts_ = pagination.items
     60         return render_template('manager_post.html',
     61                                posts=posts_,
     62                                search_manager_post_form=search_manager_post_form,
     63                                order_by_id=order_by_id,
     64                                order_by_time=order_by_time,
     65                                pagination=pagination)
     66     return render_template('manager_post.html',
     67                            posts=posts,
     68                            search_manager_post_form = search_manager_post_form,
     69                            order_by_id=order_by_id,
     70                            order_by_time=order_by_time,
     71                            pagination=pagination)
     72 
     73 #修改                           
     74 @bbs_admin.route('/edit_manager_post/<post_id>',methods=['GET','POST'])
     75 @login_required
     76 @is_manager
     77 def edit_manager_post(post_id):
     78     edit_manager_post_form = EditManagerPostForm()
     79     post1 = Post.query.filter_by(id=post_id).first()
     80     if edit_manager_post_form.validate_on_submit():
     81         post1.title = edit_manager_post_form.title.data
     82         post1.body = edit_manager_post_form.body.data
     83         post1.can_seen = edit_manager_post_form.can_seen.data
     84         post1.is_best = edit_manager_post_form.is_best.data
     85         post1.is_top = edit_manager_post_form.is_top.data
     86         db.session.add(post1)
     87         db.session.commit()
     88         return redirect(url_for('bbs_admin.manager_post',order_by_id=0,order_by_time=0))
     89     edit_manager_post_form.title.data = post1.title
     90     edit_manager_post_form.body.data = post1.body
     91     edit_manager_post_form.can_seen.data = post1.can_seen
     92     edit_manager_post_form.is_best.data = post1.is_best
     93     edit_manager_post_form.is_top.data = post1.is_top
     94     return render_template('edit_manager_post.html',
     95                            post1=post1,
     96                            edit_manager_post_form=edit_manager_post_form)
     97                            
     98                            
     99 #前端页面
    100 --manager_post.html--
    101 {% extends 'admin_base.html' %}
    102 {% block title %} 帖子管理 {% endblock %}
    103 {% block contnet %}
    104     <h1>帖子管理</h1>
    105     <form method="post" action="{{ url_for('bbs_admin.manager_post',order_by_id=0,order_by_time=0) }}">
    106           {{ search_manager_post_form.hidden_tag() }}
    107         {{ search_manager_post_form.search }}
    108         {{ search_manager_post_form.kind }}
    109         {{ search_manager_post_form.submmit }}
    110     </form>
    111     <a href="{{ url_for('bbs_admin.manager_post',order_by_id=0,order_by_time=0) }}">显示全部</a>
    112     <hr>
    113     <table border="1">
    114     <thead>
    115         <tr>
    116             {% if order_by_id==1 and order_by_time==0 %}
    117                 <td><a href="{{ url_for('bbs_admin.manager_post',order_by_id=0,order_by_time=0) }}#">ID(倒叙)</a></td>
    118             {% else %}
    119                 <td><a href="{{ url_for('bbs_admin.manager_post',order_by_id=1,order_by_time=0) }}#">ID(正序)</a></td>
    120             {% endif %}
    121             <td>作者</td>
    122             <td>标题</td>
    123             <td>内容</td>
    124             {% if order_by_id==0 and order_by_time==1 %}
    125                 <td><a href="{{ url_for('bbs_admin.manager_post',order_by_id=0,order_by_time=0) }}">创建时间(倒序)</a></td>
    126             {% else %}
    127                 <td><a href="{{ url_for('bbs_admin.manager_post',order_by_id=0,order_by_time=1) }}">创建时间(正序)</a></td>
    128             {% endif %}
    129             <td>最后修改</td>
    130             <td>评论数</td>
    131             <td>赞</td>
    132             <td>可读</td>
    133             <td>置顶</td>
    134             <td>加精</td>
    135             <td>操作</td>
    136         </tr>
    137     </thead>
    138         {% for post in posts %}
    139             <tr>
    140                 <td>{{ post.id }}</td>
    141                 <td>{{ post.user.username }}</td>
    142                 <td>{{ post.title }}</td>
    143                 <td>{{ post.body }}</td>
    144                 <td>{{ post.create_time }}</td>
    145                 <td>{{ post.last_modify_time }}</td>
    146                 <td>{{ post.comment | length }}</td>
    147                 <td>{{ post.zancai | length }}</td>
    148                 <td>{{ post.can_seen }}</td>
    149                 <td>{{ post.is_top }}</td>
    150                 <td>{{ post.is_best }}</td>
    151                 <td><a href="{{ url_for('bbs_admin.edit_manager_post',post_id=post.id) }}">修改</a>|<a href="#">删除</a></td>
    152             </tr>
    153         {% endfor %}
    154     </table>
    155     《-{% for p in pagination.iter_pages() %}
    156         <a href="{{ url_for('bbs_admin.manager_post',page= p,order_by_id=0,order_by_time=0) }}">{{ p }}</a>
    157     {% endfor %}-158 {% endblock %}
    View Code

    4.2.3 评论管理

    评论的删改、屏蔽

     1 评论管理主要就是帖子的屏蔽,需要管理员权限
     2 
     3 #表单类
     4 --bbs/bbs_admin/forms.py--
     5 class EditManagerCommentForm(FlaskForm):
     6     body = StringField()
     7     can_seen = BooleanField()
     8     submmit = SubmitField('提交')
     9     
    10 
    11 #业务逻辑
    12 --bbs/bbs_admin/views.py--
    13 #查询
    14 @bbs_admin.route('/manager_comment')
    15 @login_required
    16 @is_manager
    17 def manager_comment():
    18     page = request.args.get('page',1,type=int)
    19     pagination = Comment.query.paginate(page,per_page=10,error_out=False)
    20     comments = pagination.items
    21     return render_template('manager_comment.html',
    22                            comments=comments,
    23                            pagination=pagination)
    24 
    25 #修改
    26 @bbs_admin.route('/edit_manager_comment/<comment_id>',methods=['GET','POST'])
    27 @login_required
    28 @is_manager
    29 def edit_manager_comment(comment_id):
    30     edit_manager_comment_form = EditManagerCommentForm()
    31     comment1 = Comment.query.filter_by(id=comment_id).first()
    32     if edit_manager_comment_form.validate_on_submit():
    33         comment1.body = edit_manager_comment_form.body.data
    34         comment1.can_seen = edit_manager_comment_form.can_seen.data
    35         db.session.add(comment1)
    36         db.session.commit()
    37         return redirect(url_for('bbs_admin.manager_comment'))
    38     edit_manager_comment_form.body.data = comment1.body
    39     edit_manager_comment_form.can_seen.data = comment1.can_seen
    40     return render_template('edit_manager_comment.html',
    41                            comment1=comment1,
    42                            edit_manager_comment_form=edit_manager_comment_form)
    43                            
    44 
    45 #前端页面
    46 --manager_comment.html--
    47 {% extends 'admin_base.html' %}
    48 {% block title %} 评论修改 {% endblock %}
    49 {% block contnet %}
    50     <h1>评论修改</h1>
    51     <hr>
    52     <form method="POST" action="{{ url_for('bbs_admin.edit_manager_comment',comment_id=comment1.id) }}">
    53     {{ edit_manager_comment_form.hidden_tag() }}
    54     <table border="1">
    55     <thead>
    56         <tr>
    57             <td>ID</td>
    58             <td>所属帖子</td>
    59             <td>评论者</td>
    60             <td>被评论者</td>
    61             <td>内容</td>
    62             <td>创建时间</td>
    63             <td>顶级评论</td>
    64             <td>可读</td>
    65             <td>操作</td>
    66         </tr>
    67     </thead>
    68        <tr>
    69             <td>{{ comment1.id }}</td>
    70             <td>{{ comment1.post.title }}</td>
    71             <td>{{ comment1.user.username }}</td>
    72             {% if comment1.is_top_comment %}
    73                 <td>顶级评论</td>
    74                 {% else %}
    75                 <td>{{ comment1.parent_comment.user.username }}</td>
    76             {% endif %}
    77             <td>{{ edit_manager_comment_form.body }}</td>
    78             <td>{{ comment1.create_time }}</td>
    79             <td>{{ comment1.is_top_comment }}</td>
    80             <td>{{ edit_manager_comment_form.can_seen }}</td>
    81             <td>{{ edit_manager_comment_form.submmit }}|<a href="{{ url_for('bbs_admin.manager_comment') }}">取消</a></td>
    82         </tr>
    83     </table>
    84     </form>
    85 {% endblock %}
    View Code

    4.2.4 用户管理

    用户角色修改

     

     1 用户管理主要是用过权限角色的任命
     2 需要最高管理员权限
     3 
     4 #表单类
     5 --bbs/bbs_admin/forms.py--
     6 class EditManagerUserForm(FlaskForm):
     7     role = SelectField(coerce=int)
     8     description = StringField()
     9     is_star_user = BooleanField()
    10     submmit = SubmitField('提交')
    11     #初始化时载入所有角色
    12     def __init__(self,*args,**kwargs):
    13         super(EditManagerUserForm,self).__init__(*args,**kwargs)
    14         self.role.choices = [(role.id,role.role_name) for role in Role.query.order_by(Role.role_name).all()]
    15         
    16         
    17 #业务逻辑
    18 --bbs/bbs_admin/views.py--
    19 #查询
    20 @bbs_admin.route('/manager_user')
    21 @login_required
    22 @is_admin
    23 def manager_user():
    24     page = request.args.get('page',1,type=int)
    25     pagination = User.query.paginate(page,per_page=10,error_out=False)
    26     users = pagination.items
    27     return render_template('manager_user.html',users=users,pagination=pagination)
    28 
    29 #修改
    30 @bbs_admin.route('/edit_manager_user/<user_id>',methods=['GET','POST'])
    31 @login_required
    32 @is_admin
    33 def edit_manager_user(user_id):
    34     edit_manager_user_form = EditManagerUserForm()
    35     user1 = User.query.filter_by(id = user_id).first()
    36     if edit_manager_user_form.validate_on_submit():
    37         user1.role_id = edit_manager_user_form.role.data
    38         user1.description = edit_manager_user_form.description.data
    39         user1.is_star_user = edit_manager_user_form.is_star_user.data
    40         db.session.add(user1)
    41         db.session.commit()
    42         return redirect(url_for('bbs_admin.manager_user'))
    43     edit_manager_user_form.role.data = user1.role_id
    44     edit_manager_user_form.description.data = user1.description
    45     return render_template('edit_manager_user.html',
    46                            user1=user1,
    47                            edit_manager_user_form = edit_manager_user_form)
    48                            
    49                            
    50 #前端页面
    51 --manager_user.html--
    52 {% extends 'admin_base.html' %}
    53 {% block title %} 用户管理 {% endblock %}
    54 {% block contnet %}
    55     <h1>用户管理</h1>
    56     <hr>
    57     <table border="1">
    58     <thead>
    59         <tr>
    60             <td>ID</td>
    61             <td>用户名</td>
    62             <td>邮箱</td>
    63             <td>密码</td>
    64             <td>描述</td>
    65             <td>角色</td>
    66             <td>权限</td>
    67             <td>创建时间</td>
    68             <td>最后登陆</td>
    69             <td>明星用户</td>
    70             <td>操作</td>
    71         </tr>
    72     </thead>
    73     {% for user in users %}
    74         <tr>
    75             <td>{{ user.id }}</td>
    76             <td>{{ user.username }}</td>
    77             <td>{{ user.email }}</td>
    78             <td>{{ user.password }}</td>
    79             <td>{{ user.description }}</td>
    80             <td>{{ user.role.role_name }}</td>
    81             <td>{{ user.role.permissions }}</td>
    82             <td>{{ user.create_time }}</td>
    83             <td>{{ user.last_seen }}</td>
    84             <td>{{ user.is_star_user }}</td>
    85             <td><a href="{{ url_for('bbs_admin.edit_manager_user',user_id=user.id) }}">修改</a>|<a href="#">删除</a></td>
    86         </tr>
    87     {% endfor %}
    88     </table>
    89     《-{% for p in pagination.iter_pages() %}
    90         <a href="{{ url_for('bbs_admin.manager_user',page= p) }}">{{ p }}</a>
    91     {% endfor %}-92 {% endblock %}
    View Code

    5、最后总结

    毕业设计水平的练手项目,主要是为了熟悉下Web开发,总体感觉Flask用的确实比Django要灵活些

    项目还有很多缺陷和不足,在后期水平提高后在来修复

    自己用BootStrap搭前端确实很难看

    项目的上线放到下一篇博客来写吧,估计得经常查阅

     

  • 相关阅读:
    Java中的事务
    ABCDE
    Android 防内存泄露handler
    自建应用新花样,菜鸟也会做应用
    软件測试之独步武林系列(一)
    刚在在win8.1下装了ubuntu12.04
    SVN 的一些操作
    [华为机试练习题]42.求二叉树的深度和宽度
    iOS_正則表達式
    在应用中更新App版本号
  • 原文地址:https://www.cnblogs.com/cx59244405/p/10008005.html
Copyright © 2011-2022 走看看