发布帖子后台逻辑完成
首先给帖子设计个模型,编辑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\')
同步到数据库
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.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.__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!\')])
@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())
配置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.__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 %}
在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.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>