sellsa

发布帖子后台逻辑完成

首先给帖子设计个模型,编辑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>

 

分类:

技术点:

相关文章:

  • 2021-08-22
  • 2021-04-04
  • 2019-01-17
  • 2021-08-31
  • 2021-07-16
  • 2021-12-15
  • 2021-12-26
  • 2021-08-25
猜你喜欢
  • 2021-10-15
  • 2021-10-12
  • 2021-11-28
  • 2018-05-13
  • 2021-12-11
  • 2021-06-05
  • 2021-07-04
相关资源
相似解决方案