zoukankan      html  css  js  c++  java
  • Flask实战第58天:发布帖子功能完成

    发布帖子后台逻辑完成

    首先给帖子设计个模型,编辑apps.models.py

    class PostModel(db.Model):
        __tablename__ = 'post'
        id = db.Column(db.Integer, primary_key=True, autoincrement=True)
        title = db.Column(db.String(200), nullable=False)
        content = db.Column(db.Text, nullable=False)
        create_time = db.Column(db.DateTime, default=datetime.now)
        board_id = db.Column(db.Integer, db.ForeignKey('board.id'))
        author_id = db.Column(db.String(100), db.ForeignKey('front_user.id'), nullable=False)
    
        board = db.relationship("BoardModel", backref="posts")
        author = db.relationship("FrontUser", backref='posts')
    apps.models.py

    同步到数据库

    python manage.py db migrate
    python manage.py db upgrade

    发表帖子是需要前台用户登录才可以的,因此,我先完成下验证前台用户是否登录的装饰器,创建front.decorators.py

    from functools import wraps
    from flask import session, redirect, url_for
    import config
    
    def login_required(func):
        @wraps(func)
        def inner(*args, **kwargs):
            if config.FRONT_USER_ID in session:
                return func(*args, **kwargs)
            else:
                return redirect(url_for('front.signin'))
        return inner
    front.decotators.py

    写一个钩子函数,用来全局使用登录用户的信息,创建front.hooks.py

    from .views import bp
    import config
    from flask import session,g,render_template
    from .models import FrontUser
    
    
    @bp.before_request
    def my_before_request():
        if config.FRONT_USER_ID in session:
            user_id = session.get(config.FRONT_USER_ID)
            user = FrontUser.query.get(user_id)
            if user:
                g.front_user = user
    front.hooks.py

    编辑front.__init__.py

    from .views import bp
    from . import hooks

    编辑front.views.py,发布帖子的视图函数,首先写个form验证

    class AddPostForm(BaseForm):
        title = StringField(validators=[InputRequired(message='请输入标题!')])
        content = StringField(validators=[InputRequired(message='请输入内容!')])
        board_id = IntegerField(validators=[InputRequired(message='请输入板块id!')])
    front.forms.py
    @bp.route('/apost/', methods=['GET', 'POST'])
    @login_required
    def apost():
        if request.method == 'GET':
            boards = BoardModel.query.all()
            return render_template('front/front_apost.html', boards=boards)
        else:
            add_post_form = AddPostForm(request.form)
            if add_post_form.validate():
                title = add_post_form.title.data
                content = add_post_form.content.data
                board_id = add_post_form.board_id.data
                board = BoardModel.query.get(board_id)
                if not board:
                    return xjson.json_param_error(message='没有这个板块')
                post = PostModel(title=title, content=content)
                post.board = board
                post.author = g.front_user
                db.session.add(post)
                db.session.commit()
                return xjson.json_success()     
            else:
                return xjson.json_param_error(message=add_post_form.get_error())
    front.views.py

    配置UEditor富文本编辑器

    进入 下载页面 下载软件包

    解压软件包,把php目录里面的config.json复制出来,然后删除php目录

    在flask项目static目录下创建目录ueditor,把以上图中的目录文件拷贝到static/ueditor中

    编辑flask配置文件config.py,添加如下配置

    # UEditor的相关配置
    #上传到本地
    #UEDITOR_UPLOAD_PATH = os.path.join(os.path.dirname(__file__),'images')
    #上传到七牛
    UEDITOR_UPLOAD_TO_QINIU = True  #如果上传到七牛这里设置为True,上传到本地则为False
    UEDITOR_QINIU_ACCESS_KEY = "xxxxx"
    UEDITOR_QINIU_SECRET_KEY = "xxxxx"
    UEDITOR_QINIU_BUCKET_NAME = "xxxx"
    UEDITOR_QINIU_DOMAIN = "http://xxxx"

    flask需要一个视图路由来处理,这里我们配置一个蓝图

    在apps下新建一个python packge命名为ueditor, 在uedittor下新建ueditor.py

    from flask import (
        Blueprint,
        request,
        jsonify,
        url_for,
        send_from_directory,
        current_app as app
    )
    import json
    import re
    import string
    import time
    import hashlib
    import random
    import base64
    import sys
    import os
    from urllib import parse
    # 更改工作目录。这么做的目的是七牛qiniu的sdk
    # 在设置缓存路径的时候默认会设置到C:/Windows/System32下面
    # 会造成没有权限创建。
    os.chdir(os.path.abspath(sys.path[0]))
    try:
        import qiniu
    except:
        pass
    from io import BytesIO
    
    bp = Blueprint('ueditor',__name__,url_prefix='/ueditor')
    
    UEDITOR_UPLOAD_PATH = ""
    UEDITOR_UPLOAD_TO_QINIU = False
    UEDITOR_QINIU_ACCESS_KEY = ""
    UEDITOR_QINIU_SECRET_KEY = ""
    UEDITOR_QINIU_BUCKET_NAME = ""
    UEDITOR_QINIU_DOMAIN = ""
    
    @bp.before_app_first_request
    def before_first_request():
        global UEDITOR_UPLOAD_PATH
        global UEDITOR_UPLOAD_TO_QINIU
        global UEDITOR_QINIU_ACCESS_KEY
        global UEDITOR_QINIU_SECRET_KEY
        global UEDITOR_QINIU_BUCKET_NAME
        global UEDITOR_QINIU_DOMAIN
        UEDITOR_UPLOAD_PATH = app.config.get('UEDITOR_UPLOAD_PATH')
        if UEDITOR_UPLOAD_PATH and not os.path.exists(UEDITOR_UPLOAD_PATH):
            os.mkdir(UEDITOR_UPLOAD_PATH)
    
        UEDITOR_UPLOAD_TO_QINIU = app.config.get("UEDITOR_UPLOAD_TO_QINIU")
        if UEDITOR_UPLOAD_TO_QINIU:
            try:
                UEDITOR_QINIU_ACCESS_KEY = app.config["UEDITOR_QINIU_ACCESS_KEY"]
                UEDITOR_QINIU_SECRET_KEY = app.config["UEDITOR_QINIU_SECRET_KEY"]
                UEDITOR_QINIU_BUCKET_NAME = app.config["UEDITOR_QINIU_BUCKET_NAME"]
                UEDITOR_QINIU_DOMAIN = app.config["UEDITOR_QINIU_DOMAIN"]
            except Exception as e:
                option = e.args[0]
                raise RuntimeError('请在app.config中配置%s!'%option)
    
        csrf = app.extensions.get('csrf')
        if csrf:
            csrf.exempt(upload)
    
    
    def _random_filename(rawfilename):
        letters = string.ascii_letters
        random_filename = str(time.time()) + "".join(random.sample(letters,5))
        filename = hashlib.md5(random_filename.encode('utf-8')).hexdigest()
        subffix = os.path.splitext(rawfilename)[-1]
        return filename + subffix
    
    
    @bp.route('/upload/',methods=['GET','POST'])
    def upload():
        action = request.args.get('action')
        result = {}
        if action == 'config':
            config_path = os.path.join(bp.static_folder or app.static_folder,'ueditor','config.json')
            with open(config_path,'r',encoding='utf-8') as fp:
                result = json.loads(re.sub(r'/*.**/','',fp.read()))
    
        elif action in ['uploadimage','uploadvideo','uploadfile']:
            image = request.files.get("upfile")
            filename = image.filename
            save_filename = _random_filename(filename)
            result = {
                'state': '',
                'url': '',
                'title': '',
                'original': ''
            }
            if UEDITOR_UPLOAD_TO_QINIU:
                if not sys.modules.get('qiniu'):
                    raise RuntimeError('没有导入qiniu模块!')
                buffer = BytesIO()
                image.save(buffer)
                buffer.seek(0)
                q = qiniu.Auth(UEDITOR_QINIU_ACCESS_KEY, UEDITOR_QINIU_SECRET_KEY)
                token = q.upload_token(UEDITOR_QINIU_BUCKET_NAME)
                ret,info = qiniu.put_data(token,save_filename,buffer.read())
                if info.ok:
                    result['state'] = "SUCCESS"
                    result['url'] = parse.urljoin(UEDITOR_QINIU_DOMAIN,ret['key'])
                    result['title'] = ret['key']
                    result['original'] = ret['key']
            else:
                image.save(os.path.join(UEDITOR_UPLOAD_PATH, save_filename))
                result['state'] = "SUCCESS"
                result['url'] = url_for('ueditor.files',filename=save_filename)
                result['title'] = save_filename,
                result['original'] = image.filename
    
        elif action == 'uploadscrawl':
            base64data = request.form.get("upfile")
            img = base64.b64decode(base64data)
            filename = _random_filename('xx.png')
            filepath = os.path.join(UEDITOR_UPLOAD_PATH,filename)
            with open(filepath,'wb') as fp:
                fp.write(img)
            result = {
                "state": "SUCCESS",
                "url": url_for('files',filename=filename),
                "title": filename,
                "original": filename
            }
        return jsonify(result)
    
    
    @bp.route('/files/<filename>/')
    def files(filename):
        return send_from_directory(UEDITOR_UPLOAD_PATH,filename)
    ueditor.py

    编辑ueditor.__init__.py

    from .ueditor import bp

    在主程序中注册蓝图

    ...
    from apps.ueditor import bp as ueditor_bp
    
    app.register_blueprint(ueditor_bp)

    前台配置

    在templates/front下创建front_apost.html

    {% extends "front/front_base.html" %}
    
    {% block title %}
        发布帖子
    {% endblock %}
    
    {% block head %}
        <script src="{{ url_for('static',filename='ueditor/ueditor.config.js') }}"></script>
        <script src="{{ url_for('static',filename='ueditor/ueditor.all.min.js') }}"></script>
    {% endblock %}
    
    {% block body %}
    <form action="" method="post">
        <div class="form-group">
            <div class="input-group">
                <span class="input-group-addon">标题</span>
                <input type="text" class="form-control" name="title">
            </div>
        </div>
        <div class="form-group">
            <div class="input-group">
                <span class="input-group-addon">板块</span>
                <select name="board_id" class="form-control">
                    {% for board in boards %}
                        <option value="{{ board.id }}">{{ board.name }}</option>
                    {% endfor %}
    
                </select>
            </div>
        </div>
        <div class="form-group">
            <script id="editor" type="text/plain" style="height:500px;"></script>
        </div>
        <div class="form-group">
            <button class="btn btn-danger" id="submit-btn">发布帖子</button>
        </div>
    </form>
    {% endblock %}
    front_apost.html

    在static/front/js下创建front_apost.js

    /**
     * Created by Administrator on 2018/10/6.
     */
    
    /**
     * Created by hynev on 2017/12/31.
     */
    
    $(function () {
        var ue = UE.getEditor("editor",{
            "serverUrl": '/ueditor/upload/'
        });
    
        $("#submit-btn").click(function (event) {
            event.preventDefault();
            var titleInput = $('input[name="title"]');
            var boardSelect = $("select[name='board_id']");
    
            var title = titleInput.val();
            var board_id = boardSelect.val();
            var content = ue.getContent();
    
            bbsajax.post({
                'url': '/apost/',
                'data': {
                    'title': title,
                    'content':content,
                    'board_id': board_id
                },
                'success': function (data) {
                    if(data['code'] == 200){
                        xtalert.alertConfirm({
                            'msg': '恭喜!帖子发表成功!',
                            'cancelText': '回到首页',
                            'confirmText': '再发一篇',
                            'cancelCallback': function () {
                                window.location = '/';
                            },
                            'confirmCallback': function () {
                                titleInput.val("");
                                ue.setContent("");
                            }
                        });
                    }else{
                        xtalert.alertInfo(data['message']);
                    }
                }
            });
        });
    });
    front_apost.js

    在front_apost.html中引入front_apost.js

    {% block head %}
        ...
        <script src="{{ url_for('static',filename='front/js/front_apost.js') }}"></script>
    {% endblock %}

    编辑front_index.html

    <a href="{{ url_for("front.apost") }}" class="btn btn-warning btn-block">发布帖子</a>

     

  • 相关阅读:
    SQL性能优化:如何定位网络性能问题
    ORACLE 10升级到10.2.0.5 Patch Set遇到的内核参数检测失败问题
    Linux 僵尸进程查杀
    Linux 虚拟机网络适配器从E1000改为VMXNET3
    v$session中server为none与shared值解析
    SQL SERVER导出特殊格式的平面文件
    XtraBackup出现 Can't connect to local MySQL server through socket '/tmp/mysql.sock'
    CentOS 6.6安装Xtrabackup RPM提示缺少libev.so.4()
    SQL Server Replication 中关于视图的点滴
    ORA-00988: missing or invalid password(s)
  • 原文地址:https://www.cnblogs.com/sellsa/p/9703676.html
Copyright © 2011-2022 走看看