从零开始,构建前后端分离的博客系统二

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_38356149/article/details/85202339

后端开发历程

*注意 项目仍持续开发中,代码在持续增加或改动。如需实时代码请前往github项目地址。

后端项目github地址

  1. 项目环境搭建
    我选择pycharm作为IDE,原因是自带virtual开发环境,可视化的包管理器,最重要的一点好看。
    项目结构
    项目主要由 api组件和models.py组成, manage.py实现项目启动及部署,config.py实现项目配置。
    蓝图及其配置 可参考Blueprint

  2. 数据库建立(使用sqlalchemy orm)
    其中关系建立请参考这篇文章

    models.py

    • 注意点
      • uuid生成不能直接 放在字段的 default=uuid.uuid1, 需要str(uuid.uuid1)
      • uuid 不能放在default=后, 每次创建一条数据时,会导致uuid重复,使其unque键约束冲突
      • datetime.now() 同样不能直接放在default=后,与上一条原因一样
      • to_json方法,sqlalchemy没有提供序列化方法,所以我们需要将其查询的数据序列化
    from app import db
    from datetime import datetime
    from flask_login import UserMixin
    from werkzeug.security import generate_password_hash, check_password_hash
    import uuid
    
    
    # uuid生成
    def gen_uuid():
        return uuid.uuid1().hex
    
    
    # 时间日期生成
    def gen_time():
        return datetime.now()
    
    
    def set_info(body):
        info = body[:20]
        s = ''
        for str in info:
            s = s + str.strip('#|*`')
        return s.strip().replace(' ', ',')
    
    
    # 权限
    class Permission(db.Model):
        __tablename__ = 'permission'
        id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.String(100), unique=True)
        url = db.Column(db.String(255), unique=True)
        role = db.Column(db.Integer, db.ForeignKey('roles.id'))  # 所属组
        create_time = db.Column(db.DateTime, index=True,)
    
        def __init__(self):
            self.create_time = gen_time()
    
    
    # 标签
    class Tag(db.Model):
        __tablename__ = 'tag'
        id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.String(100), unique=True)
        create_time = db.Column(db.DateTime, index=True)
        article = db.relationship("Article", backref='tag')
    
        def __init__(self):
            self.create_time = gen_time()
    
    
    # 文章
    class Article(db.Model):
        __tablename__ = 'article'
    
        id = db.Column(db.Integer, primary_key=True)
        title = db.Column(db.String(128))
        info = db.Column(db.Text)
        body = db.Column(db.Text)
        body_html = db.Column(db.Text)
        create_time = db.Column(db.DateTime, index=True)
        star = db.Column(db.SmallInteger)
        tag_id = db.Column(db.Integer, db.ForeignKey('tag.id'))
        user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
        comments = db.relationship("Comment", backref='article')
    
        def __init__(self, title, body, body_html):
            self.title = title
            self.body = body
            self.body_html = body_html
            self.info = set_info(body)
            self.create_time = gen_time()
            # self.kind = kind
    
        def __repr__(self):
            return "<Article %r>" % self.title
    
        # json序列
        def to_json(self):
            dict = self.__dict__
            if "_sa_instance_state" in dict:
                del dict["_sa_instance_state"]
            return dict
    
    
    # 评论
    class Comment(db.Model):
        __tablename__ = 'comment'
        id = db.Column(db.Integer, primary_key=True)
        content = db.Column(db.Integer)
        user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
        article_id = db.Column(db.Integer, db.ForeignKey('article.id'))
        create_time = db.Column(db.DateTime, index=True)
    
        def __init__(self, content, user_id, article_id):
            self.content = content
            self.user_id = user_id
            self.article_id = article_id
            self.create_time = gen_time()
    
        def __repr__(self):
            return '<Comment %r>' % self.id
    
        def to_json(self):
            dict = self.__dict__
            if "_sa_instance_state" in dict:
                del dict["_sa_instance_state"]
            return dict
    
    
    # 角色
    class Role(db.Model):
        __tablename__ = 'roles'
    
        id = db.Column(db.Integer, primary_key=True)
        role_name = db.Column(db.String, unique=True)
        permission = db.relationship("Permission", backref='roles')
        user = db.relationship('User', backref='roles', lazy='dynamic')
    
        @staticmethod
        def insert_roles():
            roles = ['管理员', '普通用户']
            for r in roles:
                role = Role.query.filter_by(role_name=r).first()
                if role is None:
                    role = Role(role_name=r)
                db.session.add(role)
            db.session.commit()
    
        def __repr__(self):
            return '' % (self.id, self.name)
    
        # json序列化
        def to_json(self):
            dict = self.__dict__
            if "_sa_instance_state" in dict:
                del dict["_sa_instance_state"]
            return dict
    
    
    # 用户
    class User(db.Model, UserMixin):
        # 表名
        __tablename__ = 'user'
        # 字段
        id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.String(16), unique=True)
        create_time = db.Column(db.DateTime, index=True)
        password_hash = db.Column(db.String(128))
        face = db.Column(db.String(255), unique=True)
        uuid = db.Column(db.String(255), unique=True)
        role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
        article = db.relationship('Article', backref='user', lazy='dynamic')
        user_logs = db.relationship('Userlog', backref='user')  # 会员日志外键关系关联
        admin_logs = db.relationship('Adminlog', backref='user') # 管理员外键关系关联
        comments = db.relationship('Comment', backref='user')  # 评论外键关联
    
        def __init__(self, name, password, role):
            self.name = name
            self.password_hash = generate_password_hash(password)
            self.role_id = role
            self.uuid = gen_uuid()
            self.create_time = gen_time()
    
        @staticmethod
        def insert_admin():
            admin = User.query.filter_by(name='yker').first()
            if admin is None:
                admin = User(name='yker', password='yker123', role=1)
            db.session.add(admin)
            db.session.commit()
    
        def __repr__(self):
            return '' % (self.id, self.name)
    
        # json序列化
        def to_json(self):
            dict = self.__dict__
            if "_sa_instance_state" in dict:
                del dict["_sa_instance_state"]
            return dict
    
        def verify_password(self, password):
            if self.password_hash is None:
                return False
            else:
                return check_password_hash(self.password_hash, password)
    
    
    # 会员登录日志
    class Userlog(db.Model):
        __tablename__ = 'userlog'
        id = db.Column(db.Integer, primary_key=True)
        user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
        ip = db.Column(db.String(100))
        create_time = db.Column(db.DateTime, index=True)
    
        def __init__(self):
            self.create_time = gen_time()
    
        def to_json(self):
            dict = self.__dict__
            if "_sa_instance_state" in dict:
                del dict["_sa_instance_state"]
            return dict
    
    
    # 管理员日志
    class Adminlog(db.Model):
        __tablename__ = 'adminlog'
        id = db.Column(db.Integer, primary_key=True)
        admin_id = db.Column(db.Integer, db.ForeignKey('user.id'))
        ip = db.Column(db.String(100))
        create_time = db.Column(db.DateTime, index=True)
    
        def __init__(self):
            self.create_time = gen_time()
    
        def __repr__(self):
            return "<Admin %r>" % self.id
    
        def to_json(self):
            dict = self.__dict__
            if "_sa_instance_state" in dict:
                del dict["_sa_instance_state"]
            return dict
    
    
    # 操作日志
    class Oplog(db.Model):
        __tablename__ = 'oplog'
        id = db.Column(db.Integer, primary_key=True)
        admin_id = db.Column(db.Integer, db.ForeignKey('user.id'))
        ip = db.Column(db.String(100))
        reason = db.Column(db.String(600))
        create_time = db.Column(db.DateTime, index=True)
    
        def __init__(self, reason):
            self.create_time = gen_time()
            self.reason = reason
    
        def __repr__(self):
            return "<opmin %r>" % self.id
    
        def to_json(self):
            dict = self.__dict__
            if "_sa_instance_state" in dict:
                del dict["_sa_instance_state"]
            return dict
    
    
    
    
  3. api接口开发
    通常来说,开发前后端分离项目时,需要与前端人员约定api准侧,由于是个人开发,所以跟自己约定下就行。

    • 注意点
      1. request 的使用参考 request
      2. 数据量多时,我们应该进行分页查询
      3. 多表联合查询时需要先进行group_by
      4. 查询时需要先order_by再分页
      5. sqlalchemy 文档请参考 sqlalchemy文档

    post.py

    from flask import jsonify, request
    from datetime import datetime
    from sqlalchemy import func
    from app.models import User, Article, Role, Adminlog, Oplog, Userlog, Comment
    from . import api
    from .. import db
    from manage import app
    # 管理员 与 普通用户
    ADMINISTRATOR = 1
    ORDINARY = 2
    
    
    # 生成log json
    def gen_json(object):
        result = []
        for obj in object:
            result.append({'id': obj.id, 'name': obj.name,
                           'create_time': obj.create_time.strftime("%Y-%m-%d %H:%M:%S"),
                           'ip': obj.ip})
        return result
    
    
    # 登录验证
    @api.route('/api/login', methods=['POST'])
    def login():
        user = User.query.filter_by(name=request.form.get('name')).first()
        password = request.form.get('password')
    
        if user is not None and user.verify_password(password=password):
            user_log = Userlog(user_id=user.id)
            db.session.add(user_log)
            db.session.commit()
            return jsonify({'is_authorization': 'true', 'id': user.id,
                            'name': request.form.get('name'),
                            'token': user.uuid, 'status': 200})
    
    
    # 注册
    @api.route('/api/register', methods=['POST'])
    def register():
        name = request.form.get('name')
        password = request.form.get('password')
        if name and password:
            result = User.query.filter_by(name=name).count()
            if result is not 0:
                user = User(name=name, password=password, role=ORDINARY)
                db.session.add(user)
                db.session.commit()
                op_log = Oplog(reason='用户注册')
                db.session.add(op_log)
                db.session.commit()
                users = User.query.filter_by(name=request.form.get('name')).first()
                return jsonify({'is_authorization': 'true', 'name': users.name,
                                'token': users.uuid, 'status': 200})
            return jsonify({'flag': 'error', 'reason': '该账号已经注册', 'status': 400})
        return jsonify({'flag': 'error', 'status': 400})
    
    
    # 用户api 增删改查
    @api.route('/api/user', methods=['GET'])
    def get_user():
        page_size = request.args.get('page_size')
        users = User.query.filter_by(role_id=ORDINARY).\
            outerjoin(Role).add_columns(User.id,
                                        User.name,
                                        User.uuid,
                                        User.create_time,
                                        Role.role_name).\
            paginate(int(page_size), per_page=10, error_out=False)
        result = []
        for user in users.items:
            result.append({'id': user.id, 'name': user.name, 'role': user.role_name,
                           'create_time': user.create_time.strftime("%Y-%m-%d %H:%M:%S"),
                           'uuid': user.uuid})
        return jsonify({'userData': result, 'user_total': users.total, 'status': 200})
    
    
    @api.route('/api/user', methods=['POST'])
    def add_user():
        if not request.json or not 'name' in request.json or not 'password' in request.json:
            return jsonify({'status': 400})
    
        name = request.json['name']
        password = request.json['password']
    
        result = User.query.filter_by(name=name).count()
        if result is not 0:
            return jsonify({'flag': 'error', 'reason': '该账号已经注册', 'status': 400})
    
        user = User(name=name, password=password, role=ORDINARY)
        db.session.add(user)
        db.session.commit()
        op_log = Oplog(reason='添加用户')
        db.session.add(op_log)
        db.session.commit()
    
        return jsonify({'flag': 'success',
                        'status': 200})
    
    
    @api.route('/api/user', methods=['PUT'])
    def update_user():
        pass
    
    
    @api.route('/api/user/<int:id>', methods=['DELETE'])
    def delete_user(id):
        if id is None and User.query.filter_by(id=id).first() is None:
            return jsonify({'status': 400})
    
        user = User.query.filter_by(id=id).first()
        db.session.delete(user)
        op_log = Oplog(reason='删除用户')
        db.session.add(op_log)
        db.session.commit()
        return jsonify({'flag': 'success', 'status': 200})
    
    
    # 文章api
    # 获得所有文章
    @api.route('/api/article', methods=['GET'])
    def get_all_article():
        page_size = request.args.get('page_size')
    
        articles = db.session.query(Article, func.count(Comment.article_id).
                                    label('number')).outerjoin(Comment).\
            group_by(Article.id).add_columns(Article.id,
                                             Article.title,
                                             Article.create_time,
                                             Article.info,
                                             Article.star). \
            paginate(int(page_size), per_page=4, error_out=False)
    
        result = []
        for article in articles.items:
            result.append({
                'id': article.id,
                'title': article.title,
                'info': article.info,
                'star': article.star,
                'number': article.number,
                'create_time': article.create_time.strftime("%Y-%m-%d %H:%M:%S")
            })
    
        return jsonify({'articleList': result, 'total': articles.total, 'status': 200})
    
    
    # 根据文章id获取文章
    @api.route('/api/article/<int:id>', methods=['GET'])
    def get_article(id):
        if id is None and Article.query.filter_by(id=id).first() is None:
            return jsonify({'status': 400})
        articles = Article.query.filter_by(id=id).add_columns(Article.id, Article.title, Article.create_time,
                                                              Article.body_html)
        result = []
        for article in articles:
            result.append({'id': article.id, 'title': article.title,
                           'create_time': article.create_time.strftime("%Y-%m-%d %H:%M:%S"),
                           'html': article.body_html})
        return jsonify({'articleContent': result, 'status': 200})
    
    
    # 添加文章
    @api.route('/api/article', methods=['POST'])
    def add_article():
        if not request.json or not 'title' in request.json or not 'body' in request.json \
                or not 'body_html' in request.json:
            return jsonify({'status': 400})
    
        article = Article(title=request.json['title'], body=request.json['body'],
                          body_html=request.json['body_html'])
        op_log = Oplog(reason='发布文章')
        db.session.add(article)
        db.session.add(op_log)
        db.session.commit()
        return jsonify({'flag': 'success', 'status': 200})
    
    
    # 更新文章
    @api.route('/api/article/<int:id>', methods=['put'])
    def update_article():
        pass
    
    
    @api.route('/api/article/<int:id>', methods=['DELETE'])
    def delete_article(id):
        if id is None and Article.query.filter_by(id=id).first() is None:
            return jsonify({'status': 400})
        article = Article.query.filter_by(id=id).first()
        op_log = Oplog(reason='删除文章')
        db.session.delete(article)
        db.session.add(op_log)
        db.session.commit()
        return jsonify({'flag': 'success', 'status': 200})
    
    
    # 角色设置
    @api.route('/api/role', methods=['GET'])
    def get_role():
        roles = Role.query.all()
        return jsonify({'roleData': [role.to_json() for role in roles], 'status': 200})
    
    
    @api.route('/api/role', methods=['POST'])
    def add_role():
        name = request.json['name']
    
        if name is not None:
            role = Role(role_name=name)
            db.session.add(role)
            db.session.commit()
    
            return jsonify({'flag': 'success', 'status': 200})
        else:
            return jsonify({'status': 400})
    
    
    @api.route('/api/role/<int:id>', methods=['DELETE'])
    def delete_role(id):
        if id is None and Role.query.filter_by(id=id).first() is None:
            return jsonify({'status': 400})
    
        role = Role.query.filter_by(id=id).first()
        db.session.delete(role)
        op_log = Oplog(reason='删除角色')
        db.session.add(op_log)
        db.session.commit()
        return jsonify({'flag': 'success', 'status': 200})
    
    
    # 管理员
    @api.route('/api/admin', methods=['GET'])
    def get_admin():
        page_size = request.args.get('page_size')
        admins = User.query.filter_by(role_id=ADMINISTRATOR).\
            outerjoin(Role).add_columns(User.id,
                                        User.name,
                                        User.uuid,
                                        User.create_time,
                                        Role.role_name).\
            paginate(int(page_size), per_page=10, error_out=False)
        result = []
        for admin in admins.items:
            result.append({'id': admin.id, 'name': admin.name,
                           'role': admin.role_name,
                           'create_time': admin.create_time.strftime("%Y-%m-%d %H:%M:%S"),
                           'uuid': admin.uuid})
    
        return jsonify({'adminData': result, 'admin_total': admins.total, 'status': 200})
    
    
    @api.route('/api/admin', methods=['POST'])
    def add_admin():
        if not request.json or not 'name' in request.json or not 'password' in request.json:
            return jsonify({'status': 400})
    
        name = request.json['name']
        password = request.json['password']
    
        result = User.query.filter_by(name=name).count()
        if result is not 0:
            return jsonify({'flag': 'error', 'reason': '该账号已经注册', 'status': 400})
    
        admin = User(name=name, password=password, role=ADMINISTRATOR)
        db.session.add(admin)
        db.session.commit()
        op_log = Oplog(reason='添加管理员')
        db.session.add(op_log)
        db.session.commit()
    
        return jsonify({'flag': 'success',
                        'status': 200, })
    
    
    @api.route('/api/admin/<int:id>', methods=['DELETE'])
    def delete_admin(id):
        if id is None and User.query.filter_by(id=id).first() is None:
            return jsonify({'status': 400})
    
        admin = User.query.filter_by(id=id).first()
        db.session.delete(admin)
        op_log = Oplog(reason='删除管理员')
        db.session.add(op_log)
        db.session.commit()
        return jsonify({'flag': 'success', 'status': 200})
    
    
    # 评论
    @api.route('/api/comment', methods=['GET'])
    def get_comment():
        article_id = request.args.get('article')
        page_size = request.args.get('page_size')
        if page_size is None and Comment.query.filter_by(article_id=article_id).all() is None:
            return jsonify({'status': 400})
        comments = Comment.query.filter_by(article_id=article_id).outerjoin(User)\
            .add_columns(
            Comment.content, Comment.create_time, User.name, User.face
        ).order_by(Comment.create_time.desc()).paginate(int(page_size), per_page=20, error_out=False)
    
        result = []
        for comment in comments.items:
            result.append({'author': comment.name, 'content': comment.content,
                           'avatar': comment.face, 'create_time': comment.create_time.strftime("%Y-%m-%d %H:%M:%S")})
        return jsonify({'comment': result, 'comment_total': comments.total, 'status': 200})
    
    
    @api.route('/api/comment', methods=['POST'])
    def add_comment():
        if request.json['id'] and \
                request.json['content'] and request.json['article_id'] is None:
            return jsonify({'status': 400})
        comment = Comment(content=request.json['content'],
                          user_id=request.json['id'], article_id=request.json['article_id'])
        db.session.add(comment)
        db.session.commit()
        return jsonify({'flag': 'success', 'status': 200})
    
    
    # 权限管理
    
    
    # 日志
    @api.route('/api/admin_log', methods=['GET'])
    def get_admin_log():
        page_size = request.args.get('page_size')
        logs = Adminlog.query.outerjoin(User).add_columns(Adminlog.id,
                                                          User.name,
                                                          Adminlog.ip,
                                                          Adminlog.create_time).\
            paginate(int(page_size), per_page=10, error_out=False)
    
        return jsonify({'AdminLog': gen_json(logs.items),
                        'adminLog_total': logs.total,
                        'status': 200})
    
    
    @api.route('/api/user_log', methods=['GET'])
    def get_user_log():
        page_size = request.args.get('page_size')
        logs = Userlog.query.outerjoin(User).add_columns(Userlog.id,
                                                         User.name,
                                                         Userlog.ip,
                                                         Userlog.create_time).\
            paginate(int(page_size), per_page=10, error_out=False)
    
        return jsonify({'UserLog': gen_json(logs.items),
                        'userLog_total': logs.total,
                        'status': 200})
    
    
    @api.route('/api/op_log', methods=['GET'])
    def get_op_log():
        page_size = request.args.get('page_size')
        logs = Oplog.query.outerjoin(User).add_columns(Oplog.id,
                                                       User.name,
                                                       Oplog.ip,
                                                       Oplog.create_time,
                                                       Oplog.reason).\
            paginate(int(page_size), per_page=10, error_out=False)
        result = []
        for obj in logs.items:
            result.append({'id': obj.id, 'name': obj.name,
                           'create_time': obj.create_time.strftime("%Y-%m-%d %H:%M:%S"),
                           'ip': obj.ip, 'reason': obj.reason})
        return jsonify({'OpLog': result, 'op_total': logs.total, 'status': 200})
    
    
    

完整项目请前往我的github

未完待续。。。

猜你喜欢

转载自blog.csdn.net/qq_38356149/article/details/85202339