Python学习笔记:6.3.12 flask-dropzone插件

前言:本文是学习网易微专业的《python全栈工程师 - Flask高级建站》课程的笔记,欢迎学习交流。同时感谢老师们的精彩传授!

一、课程目标

  • flask-dropzone插件介绍
  • flask-dropzone参数配置
  • flask-dropzone前端模版
  • flask-dropzone后端处理

二、详情解读

2.1.flask-dropzone介绍
2.1.1.flask-dropzone插件

flask-dropzone,是基于dropzone.js开发的插件,实现了前端拖拽上传,上传进度显示,上传完成显示的插件,开发人员只需要编写很少的代码就可以完成一个用户体验很好的上传功能。
插件安装:

pipenv install flask-dropzone

安装完成后生成模块flask_dropzone
在这里插入图片描述

2.2.flask-dropzone配置
配置参数 说明 默认值
DROPZONE_MAX_FILE_SIZE 最大文件上传尺寸,单位MB 3
DROPZONE_INPUT_NAME 上传域name属性值 file
DROPZONE_MAX_FILES 一次最多上传文件数量 null
DROPZONE_DEFAULT_MESSAGE 默认提示 “Drop files here to upload”
DROPZONE_FILE_TOO_BIG 文件尺寸超过限度提示 “File is too big {{filesize}.
Max filesize:{{maxFilessize}}MiB.”
DROPZONE_SERVER_ERROR 服务器错误 “Server error:{{statusCode}}”
DROPZONE_MAX_FILE_EXCEED 一次上传文件数量超限 “You can’t upload any more files.”
DROPZONE_UPLOAD_MULTIPLE 禁止一次上传多个文件 False
DROPZONE_REDIRECT_VIEW 上传完成后是否跳转 False
DROPZONE_ALLOWED_FILE_TYPE 允许文件上传类型 default
DROPZONE_ALLOWED_FILE_CUSTOM 自定义允许上传类型 自定义允许上传类型
DROPZONE_INVALID_FILE_TYPE 文件类型错误提示 “You can’t upload files of this type.”
DROPZONE_ENABLE_CSRF 是否启用csrf保护 False
DROPZONE_TIMEOUT 上传超时时间,默认30s None
DROPZONE_SERVE_LOCAL 是否加载本地的js插件资源 False
2.2.1.flask-dropzone默认允许文件类型
允许类型配置参数值 默认值
default image/*, audio/*, video/*, text/*, application/*
image image/*
audio audio/*
video video/*
text text/*
app application/*
2.2.2.初始化插件
# libs.py:
from flask_dropzone import Dropzone
dropzone = Dropzone()

# app.py:
dropzone.init_app(app)

实操:
Step1:修改settings.py文件,增加flask-dropzone配置

.
.
.
CKEDITOR_FILE_BROWSER = "upload.ckeditor_browser"

# 新增下面的配置++
# Dropzone配置
DROPZONE_MAX_FILE_SIZE = 3
DROPZONE_MAX_FILES = 30
DROPZONE_ALLOWED_FILE_CUSTOM = True
DROPZONE_ALLOWED_FILE_TYPE = 'image, .jpg, .pdf, .txt'
DROPZONE_ENABLE_CSRF = True
# 上传域名字为upload
DROPZONE_INPUT_NAME = 'upload'
.
.
.

Step2:修改libs.py文件:导入flask-dropzone并实例化

from flask import session, redirect, url_for
from functools import wraps
from flask_wtf.csrf import CSRFProtect
from flask_ckeditor import CKEditor
# 新增下面这一行
from flask_dropzone import Dropzone

# 创建数据库对象
# 这里不用传入app实例对象,因为这里尚未创建app实例
db=SQLAlchemy()
csrf = CSRFProtect()
ckeditor = CKEditor()
# 新增下面这一行
dropzone = Dropzone()
.
.
.

Step3:修改app.py文件,导入flask-dropzone并初始化

from flask import Flask, render_template
from flask import request, redirect, url_for
# 新增下面这一行: 导入dropzone
from libs import db, ckeditor, csrf, dropzone
.
.
.
db.init_app(app)
ckeditor.init_app(app)
csrf.init_app(app)
# 新增下面这一行:初始化dropzone
dropzone.init_app(app)
.
.
.
2.3.前端模版

flask-dropzone插件与flask-ckeditor一样,都是基于前端的一些框架开发的后端插件,最后要在模版生成前端插件

可以使用下面代码,加载静态的jscss资源

{{ dropzone.load_css() }}
{{ dropzone.load_js() }}
{{ dropzone.style() }} // 自定义样式
2.3.1.使用本地资源

可以Dropzone官网下载相应的静态资源:
官网地址:dropzonejs.com
官方推荐使用远程CDN资源

在需要创建上传的区域:

{{ dropzone.create(action="upload.dropzone_upload")}}

使用:{{ dropzone.config()}}加载配置

2.4.上传处理

在视图函数中,与flask-ckeditor一样,上传完成后,需要返回数据,不同的是,自己要在前端定义ajax回调函数,事件配置:https://www.dropzonejs.com/#event-success

dropzone.config(custom_init='this.on("success", function(file, res) {
	if (file.xhr.status == 200) {
		$('#thumb').val(res.file)
	} else {
		alert('上传失败')
	}
}')
2.4.1.flask.jsonify与json模块区别

如果希望传递json数据,使用jquery时,jquery会根据设置,自动将后台返回的json串转换为json对象,但是dropzone还需要根据响应头来确定是否转换为json对象,使用json模块,只是将数据转换为了json串,并不能输出正确的响应头。
Python学习笔记:6.3.12 flask-dropzone插件_第1张图片

2.4.2.文章发布前端模版

css部分插入:

{{ dropzone.load_css() }}

js部分插入:

{{ dropzone.load_js() }}

插入回调上传后回调处理:

{{ dropzone.config(custom_init(...)) }}

实操:
Step1:修改models.py文件,在Article()模型中添加thumb字段,记得更新数据库(开发环境下,如果更新出错,可以删除数据库重新建库。生产环境下更新出错就不要这样做了!!)

.
.
.
class Article(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String)
    # 新增下面这一行
    thumb = db.Column(db.String)
    intro = db.Column(db.String)
    content = db.Column(db.Text)
    author = db.Column(db.String)
    pubdate = db.Column(db.DateTime, default=datetime.utcnow)
    cate_id = db.Column(db.Integer, db.ForeignKey("category.cate_id"))
.
.
.

Step2
修改templates/memeber/article/artilce_post.html内容:

.
.
.
{% block content %}

{{ dropzone.load_css() }}
{{ dropzone.load_js() }}
<div class="container-fluid">
	<div class="row">				
		<div class="main col-md-12 col-lg-12 col-xs-12 col-sm-12" >
				<h3>文章发布h3>
                     <div class="alert alert-info" id="message" role="alert">
.
.
.
<div class="form-group">
	<label for="name">标题:label>
	<input class="form-control"  type="text" name="title" id="title" value="" placeholder="文章标题">
	
	   {{ dropzone.create(action="upload.ckeditor_upload") }}
        <input type="hidden" name="thumb" id="thumb">
    div>
.
.
.
				div>
			div>
		div>
		{# 新增下面的dropzone配置 #}
			{# 这里一定要将后台的上传视图返回的数据使用flask.jsonify处理 #}
             {{   dropzone.config(
                        custom_init='this.on("success", function(file, res) {
                        if( file.xhr.status == 200 ){
                           $("#thumb").val(res.url)
                           console.log(res)
                        }else{
                            alert("上传失败");
                        }
                         });'
                    )
             }}
            <script src="{{ url_for('static', filename='ckeditor/ckeditor.js') }}">script>
            {# 新增下面两个js脚本 #}
            <script>
                CKEDITOR.replace( 'content',{
                    filebrowserUploadUrl :'/upload/ckeditor',
                    filebrowserBrowseUrl:'/upload/ckeditor/browser',
                    //CSRF启用后,需要按照CSRF要求传递CSRF_TOKEN
                    fileTools_requestHeaders :{
                             'X-Requested-With': 'XMLHttpRequest',
                             'X-CSRF-Token': '{{ csrf_token() }}'
                           }
                })
            script>
            <script>
                btn = document.getElementById("btn1")
                btn.onclick = function (ev) {
                    cate_id = $("#cate").val()
                    title = $("#title").val()
                    thumb = $("#thumb").val()
                    intro = $("#intro").val()
                    content = CKEDITOR.instances["content"].getData()

                    if (title == ""){
                        $("#title").focus()
                        return false
                    }
                    if (intro == ""){
                        $("#intro").focus()
                        return false
                    }

                    $.ajax({
                         type:"post",
                         data:{"cate":cate_id,
                               "title":title,
                               "thumb":thumb,
                               "intro":intro,
                               "content":content
                               },
                         dataType:"json",
                         beforeSend:function(xhr){
                            xhr.setRequestHeader("X-CSRFToken", "{{  csrf_token() }}")
                         },
                         success: function(data){
                             $("#message").html(data.message)
                             //表单重置,相当于点击重设按钮
                             $("#title").val("")
                             $("#intro").val()
                             // 清空隐藏域
                             $("#thumb").val("")
                             // 清空上传
                             myDropzone.dropzone.removeAllFiles()
                             // 清空ckeditor
                             CKEDITOR.instances["content"].setData()
                         }
                    })
                }
            script>
	{% endblock %}

Step3:修改templates/index.html文件

.
.
.
<div class="col-md-6">
	
	<ul class="media-list">
       {% for article in articles %}
			<li class="media">
				<a href="" class="pull-left">
				
					<img src="{{ article.thumb }}"  class="media-object">
				a>
				<div class="media-body">
					<h4 class="media-heading">					
						<a href="{{ url_for('article_app.view', article_id=article.id) }}">
							{{ article.title }}
						a>								
					h4>
					<div class="media">
						<p>{{ article['intro'] }}p>
					div>
				div>
			li>
	   {% endfor %}
	ul>
	<ul class="pagination">
		{% for page in pageList %}
           {% if page!=None %}
				<li>
					<a href="{{ url_for('article_app.getArticleList', page=page) }}">{{ page }}a>
				li>
            {% else %}
                <li><a href="#">...a>li>
            {% endif %}
		{% endfor %}
	ul>
div>
<div class="col-md-4">
.
.
.
2.4.3.可能出现的问题

1.忘记修改模型,添加模型字段
2.忘记升级数据库(flask db migrate,flask db update
3.忘记添加ajax发送数据中添加csrf请求头
4.忘记ajax提交数据时,添加上标题图片文件地址数据(隐藏域)
5.忘记在后台视图函数中添加接收标题图数据(来自隐藏域)
6.需要在前台列表模版中,添加标题图标签

三、课程小结

  • flask-dropzone配置
  • dropzone模版渲染
  • 给文章添加标题图片

你可能感兴趣的:(Python全栈工程师学习笔记)