90行Python代码开发个人云盘应用

目录
  • 1 简介
  • 2 在Dash中实现文件上传与下载
    • 2.1 在Dash中配合dash-uploader实现文件上传
      • 2.1.1 利用du.configure_upload()进行配置
      • 2.1.2 利用du.Upload()创建上传部件
      • 2.1.3 配合du.Upload()进行回调
    • 2.2 配合flask进行文件下载
  • 3 用Dash编写简易个人网盘应用

本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes

1 简介

在今天的教程中,我们将介绍如何在Dash中高效地开发web应用中非常重要的「文件上传」及「下载」功能。

2 在Dash中实现文件上传与下载

2.1 在Dash中配合dash-uploader实现文件上传

其实在自带的dash_core_components中就封装了基于html5原生API的dcc.Upload()组件,可以实现简单的文件上传功能,但说实话,非常的「不好用」,其主要缺点有:

  • 「文件大小有限制,150M到200M左右即出现瓶颈」
  • 「策略是先将用户上传的文件存放在浏览器内存,再通过base64形式传递到服务端再次解码,非常低效」
  • 「整个上传过程无法配合准确的进度条」

正是因为Dash自带的上传部件如此不堪,所以一些优秀的第三方拓展涌现出来,其中最好用的要数dash-uploader,它解决了上面提到的dcc.Upload()的所有短板。通过pip install dash-uploader进行安装之后,就可以直接在Dash应用中使用了。

我们先从极简的一个例子出发,看一看在Dash中使用dash-uploader的正确姿势:

app1.py

import dash
import dash_uploader as du
import dash_bootstrap_components as dbc
import dash_html_components as html

app = dash.Dash(__name__)

# 配置上传文件夹
du.configure_upload(app, folder='temp')

app.layout = html.Div(
    dbc.Container(
        du.Upload()
    )
)

if __name__ == '__main__':
    app.run_server(debug=True)

可以看到,仅仅十几行代码,我们就配合dash-uploader实现了简单的文件上传功能,其中涉及到dash-uploader两个必不可少的部分:

2.1.1 利用du.configure_upload()进行配置

要在Dash中正常使用dash-uploader,我们首先需要利用du.configure_upload()进行相关配置,其主要参数有:

「app」,即对应已经实例化的Dash对象;

「folder」,用于设置上传的文件所保存的根目录,可以是相对路径,也可以是绝对路径;

「use_upload_id」,bool型,默认为True,这时被用户上传的文件不会直接置于「folder」参数指定目录,而是会存放于du.Upload()部件的upload_id对应的子文件夹之下;设置为False时则会直接存放在根目录,当然没有特殊需求还是不要设置为False。

通过du.configure_upload()我们就完成了基本的配置。

2.1.2 利用du.Upload()创建上传部件

接下来我们就可以使用到du.Upload()来创建在浏览器中渲染供用户使用的上传部件了,它跟常规的Dash部件一样具有「id」参数,也有一些其他的丰富的参数供开发者充分自由地自定义功能和样式:

「text」,字符型,用于设置上传部件内显示的文字;

「text_completed」,字符型,用于设置上传完成后显示的文字内容前缀;

「cancel_button」,bool型,用于设置是否在上传过程中显示“取消”按钮;

「pause_button」,bool型,用于设置是否在上传过程中显示“暂停”按钮;

「filetypes」,用于限制用户上传文件的格式范围,譬如['zip', 'rar', '7zp']就限制用户只能上传这三种格式的文件。默认为None即无限制;

「max_file_size」,int型,单位MB,用于限制单次上传的大小上限,默认为1024即1GB;

「default_style」,类似常规Dash部件的style参数,用于传入css键值对,对部件的样式进行自定义;

「upload_id」,用于设置部件的唯一id信息作为du.configure_upload()中所设置的缓存根目录的下级子目录,用于存放上传的文件,默认为None,会在Dash应用启动时自动生成一个随机值;

「max_files」,int型,用于设置一次上传最多可包含的文件数量,默认为1,也推荐设置为1,因为目前对于多文件上传仍有「进度条异常」、「上传结束显示异常」等bug,所以不推荐设置大于1。

知晓了这些参数的作用之后,我们就可以创建出更符合自己需求的上传部件:

app2.py

import dash
import dash_uploader as du
import dash_bootstrap_components as dbc
import dash_html_components as html

app = dash.Dash(__name__)

# 配置上传文件夹
du.configure_upload(app, folder='temp')

app.layout = html.Div(
    dbc.Container(
        du.Upload(
            id='uploader',
            text='点击或拖动文件到此进行上传!',
            text_completed='已完成上传文件:',
            cancel_button=True,
            pause_button=True,
            filetypes=['md', 'mp4'],
            default_style={
                'background-color': '#fafafa',
                'font-weight': 'bold'
            },
            upload_id='我的上传'
        )
    )
)

if __name__ == '__main__':
    app.run_server(debug=True)

但像前面的例子那样直接在定义app.layout时就传入实际的du.Upload()部件,会产生一个问题——应用启动后,任何访问应用的用户都对应一样的upload_id,这显然不是我们期望的,因为不同用户的上传文件会混在一起。

因此可以参考下面例子的方式,在每位用户访问时再渲染随机id的上传部件,从而确保唯一性:

app3.py

import dash
import dash_uploader as du
import dash_bootstrap_components as dbc
import dash_html_components as html

import uuid

app = dash.Dash(__name__)

# 配置上传文件夹
du.configure_upload(app, folder='temp')

def render_random_id_uploader():

    return du.Upload(
            id='uploader',
            text='点击或拖动文件到此进行上传!',
            text_completed='已完成上传文件:',
            cancel_button=True,
            pause_button=True,
            filetypes=['md', 'mp4'],
            default_style={
                'background-color': '#fafafa',
                'font-weight': 'bold'
            },
            upload_id=uuid.uuid1()
        )

def render_layout():

    return html.Div(
    dbc.Container(
        render_random_id_uploader()
    )
)

app.layout = render_layout

if __name__ == '__main__':
    app.run_server(debug=True)

可以看到,每次访问时由于upload_id不同,因此不同的会话拥有了不同的子目录。

2.1.3 配合du.Upload()进行回调

在du.Upload()中额外还有isCompleted与fileNames两个属性,前者用于判断当前文件是否上传完成,后者则对应此次上传的文件名称,参考下面这个简单的例子:

app4.py

import dash
import dash_uploader as du
import dash_bootstrap_components as dbc
import dash_html_components as html
from dash.dependencies import Input, Output, State

app = dash.Dash(__name__)

# 配置上传文件夹
du.configure_upload(app, folder='temp')

app.layout = html.Div(
    dbc.Container(
        [
            du.Upload(id='uploader'),
            html.H5('上传中或还未上传文件!', id='upload_status')
        ]
    )
)

@app.callback(
    Output('upload_status', 'children'),
    Input('uploader', 'isCompleted'),
    State('uploader', 'fileNames')
)
def show_upload_status(isCompleted, fileNames):
    if isCompleted:
        return '已完成上传:'+fileNames[0]

    return dash.no_update

if __name__ == '__main__':
    app.run_server(debug=True, port=8051)

2.2 配合flask进行文件下载

相较于文件上传,在Dash中进行文件的下载就简单得多,因为我们可以配合flask的send_from_directory以及html.A()部件来为指定的服务器端文件创建下载链接,譬如下面的简单示例就打通了文件的上传与下载:

app5.py

from flask import send_from_directory
import dash
import dash_uploader as du
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output
import os

app = dash.Dash(__name__)

du.configure_upload(app, 'temp', use_upload_id=False)

app.layout = html.Div(
    dbc.Container(
        [
            du.Upload(id='upload'),
            html.Div(
                id='download-files'
            )
        ]
    )
)

@app.server.route('/download/<file>')
def download(file):

    return send_from_directory('temp', file)

@app.callback(
    Output('download-files', 'children'),
    Input('upload', 'isCompleted')
)
def render_download_url(isCompleted):

    if isCompleted:
        return html.Ul(
            [
                html.Li(html.A(f'/{file}', href=f'/download/{file}', target='_blank'))
                for file in os.listdir('temp')
            ]
        )

    return dash.no_update

if __name__ == '__main__':
    app.run_server(debug=True)

3 用Dash编写简易个人网盘应用

在学习了今天的案例之后,我们就掌握了如何在Dash中开发文件上传及下载功能,下面我们按照惯例,结合今天的主要内容,来编写一个实际的案例;

今天我们要编写的是一个简单的个人网盘应用,我们可以通过浏览器访问它,进行文件的上传、下载以及删除:

import dash
import dash_bootstrap_components as dbc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import dash_uploader as du
import os
from flask import send_from_directory
import time

app = dash.Dash(__name__, suppress_callback_exceptions=True)

du.configure_upload(app, 'NetDisk', use_upload_id=False)

app.layout = html.Div(
    dbc.Container(
        [
            html.H3('简易的个人云盘应用'),
            html.Hr(),
            html.P('文件上传区:'),
            du.Upload(id='upload',
                      text='点击或拖动文件到此进行上传!',
                      text_completed='已完成上传文件:',
                      max_files=1000),
            html.Hr(),
            dbc.Row(
                [
                    dbc.Button('删除选中的文件', id='delete-btn', outline=True),
                    dbc.Button('打包下载选中的文件', id='download-btn', outline=True)
                ]
            ),
            html.Hr(),
            dbc.Spinner(
                dbc.Checklist(
                    id='file-list-check'
                )
            ),
            html.A(id='download-url', target='_blank')
        ]
    )
)

@app.server.route('/download/<file>')
def download(file):
    return send_from_directory('NetDisk', file)

@app.callback(
    [Output('file-list-check', 'options'),
     Output('download-url', 'children'),
     Output('download-url', 'href')],
    [Input('upload', 'isCompleted'),
     Input('delete-btn', 'n_clicks'),
     Input('download-btn', 'n_clicks')],
    State('file-list-check', 'value')
)
def render_file_list(isCompleted, delete_n_clicks, download_n_clicks, check_value):
    # 获取上下文信息
    ctx = dash.callback_context

    if ctx.triggered[0]['prop_id'] == 'delete-btn.n_clicks':

        for file in check_value:
            try:
                os.remove(os.path.join('NetDisk', file))
            except FileNotFoundError:
                pass

    if ctx.triggered[0]['prop_id'] == 'download-btn.n_clicks':

        import zipfile

        with zipfile.ZipFile('NetDisk/打包下载.zip', 'w') as zipobj:
            for file in check_value:
                try:
                    zipobj.write(os.path.join('NetDisk', file))
                except FileNotFoundError:
                    pass

        return [
                   {'label': file, 'value': file}
                   for file in os.listdir('NetDisk')
                   if file != '打包下载.zip'
               ], '打包下载链接', '/download/打包下载.zip'

    time.sleep(2)

    return [
               {'label': file, 'value': file}
               for file in os.listdir('NetDisk')
               if file != '打包下载.zip'
           ], '', ''

if __name__ == '__main__':
    app.run_server(debug=True)

以上就是90行Python代码开发个人云盘应用的详细内容,更多关于python 开发个人云盘的资料请关注我们其它相关文章!

(0)

相关推荐

  • Python使用百度API上传文件到百度网盘代码分享

    关于如何获取 access_token 这个可以自己查百度开放的OAuth 2.0 的 API.这里不做介绍. 第三方 Python 库 poster 复制代码 代码如下: # coding:UTF-8 import urllib import urllib2 __author__ = 'Administrator' from poster.encode import multipart_encode from poster.streaminghttp import register_opene

  • python 实现百度网盘非会员上传超过500个文件的方法

    案例故事: 百度网盘非会员大量上传文件,会弹出:"上传文件数量超出500个现在,开通超级会员后可继续上传",其实是限制拖入500张相片,并非限制上传500张. 非会员如何将众多文件,分割成500一个的文件夹,不受拖入数量限制呢? 准备阶段 os.walk()函数,可以树形遍历整个路径下的文件夹列表和文件列表 Path(路径).parent属性,可以获取该"路径"的父路径 os.path.relpath("D:\aaa\bbb\ccc",start

  • Python解析网页源代码中的115网盘链接实例

    本文实例讲述了python解析网页源代码中的115网盘链接的方法.分享给大家供大家参考.具体方法分析如下: 其中的1.txt,是网页http://bbs.pediy.com/showthread.php?t=144788另存为1.txt 具体代码如下: import re if __name__ == "__main__": fp = open("c:\\1.txt") https = re.compile(r"(http://u.*)") fo

  • Python 一键获取百度网盘提取码的方法

    该 GIF 图来自于官网,文末有给出链接. 描述 依托于百度网盘巨大的的云存储空间,绝大数人会习惯性的将一些资料什么的存储到上面,但是有的私密链接需要提取码,但是让每个想下载私密资源的人记住每一个提取码显然是不现实的.这个时候,云盘万能钥匙 诞生了,我们通过安装相应的浏览器插件就可以自动获获取相应链接的提取码.我在 Github 上看了一下,有 Web JS 版的, python 版的貌似还没有找到,所以我参照了JS 版本和官网的请求接口写了两种方式的获取脚本. 实现 下述两种方式的具体实现就不

  • Python实现115网盘自动下载的方法

    本文实例讲述了Python实现115网盘自动下载的方法.分享给大家供大家参考.具体实现方法如下: 实例中的1.txt,是网页http://bbs.pediy.com/showthread.php?t=144788另存为1.txt 通过每3秒钟复制一个下载链接到粘贴板,复制时会自动调用115客户端下载,每下载10个文件会手工输入一个字符,防止一下下载太多,卡死机器 具体代码如下: import re, os, time import webbrowser import urllib if __na

  • 90行Python代码开发个人云盘应用

    目录 1 简介 2 在Dash中实现文件上传与下载 2.1 在Dash中配合dash-uploader实现文件上传 2.1.1 利用du.configure_upload()进行配置 2.1.2 利用du.Upload()创建上传部件 2.1.3 配合du.Upload()进行回调 2.2 配合flask进行文件下载 3 用Dash编写简易个人网盘应用 本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1

  • 使用11行Python代码盗取了室友的U盘内容

    序言 那个猥琐的家伙整天把个U盘藏着当宝,到睡觉了就拿出来插到电脑上. 我决定想个办法看他U盘里都藏了什么,直接去抢U盘是不可能的,骗也是不可能的.那不是丢我Python程序员的脸? 我必须在电脑上智取,而且不能被他发现. 这个是我的思路: 当一个usb插入时,在后台自动把usb里的东西拷贝到本地或上传到某个服务器. 那么我就可以先借他电脑玩一会,然后把我写好的Python程序在电脑后台运行.每当有usb插入的时候,就自动拷贝文件. 如何判断U盘是否插入? 首先打开电脑终端,进入/Volumes

  • 仅用几行Python代码就能复制她的U盘文件?

    代码 # -*- coding:utf-8 -*- import os import time from datetime import datetime import shutil # U盘的盘符 usb_path = "E:/" # 要复制到的路径 save_path = "D:/haha" while (True):     if os.path.exists(usb_path):         shutil.copytree(usb_path, os.pa

  • 使用50行Python代码从零开始实现一个AI平衡小游戏

    集智导读: 本文会为大家展示机器学习专家 Mike Shi 如何用 50 行 Python 代码创建一个 AI,使用增强学习技术,玩耍一个保持杆子平衡的小游戏.所用环境为标准的 OpenAI Gym,只使用 Numpy 来创建 agent. 各位看官好,我(作者 Mike Shi--译者注)将在本文教大家如何用 50 行 Python 代码,教会 AI 玩一个简单的平衡游戏.我们会用到标准的 OpenAI Gym 作为测试环境,仅用 Numpy 创建我们的 AI,别的不用. 这个小游戏就是经典的

  • 150行Python代码实现带界面的数独游戏

    今天闲着没事干,以前做过html+js版的数独,这次做个python版本的,界面由pygame完成,数独生成由递归算法实现,由shuffle保证每次游戏都是不一样的情况,have fun: 功能列表: 图形化的数独游戏: python实现,依赖pygame库: 随机生成游戏,每次运行都不一样: 数字填入后的正确性判断以及颜色提示: 显示剩余需填入的空格,已经操作的次数: 难度可选,通过修改需要填入的空的数量:  游戏界面 初始界面 过程中界面 运行方式 python main.py 15 这里的

  • 20行Python代码实现一款永久免费PDF编辑工具的实现

    PDF(Portable Document Format),中文名称便携文档格式是我们经常会接触到的一种文件格式,文献.文档...很多都是PDF格式.它以格式稳定的优势,使得我们在打印.分享.传输过程中能够最优的保持原有色彩和格式. PDF是以PostScript语言图像模型为基础的一种文档格式,它在格式的稳定性方面虽然具有很大优势.但是,在可编辑性方面却为使用者引入了另外一个困扰. 例如,在文档的分割.合并.剪切.转换.编辑等方面PDF就有些捉襟见肘了. Adobe Reader.福昕阅读器.

  • 10行Python代码就能实现的八种有趣功能详解

    目录 一.生成二维码 二.生成词云 三.批量抠图 四.文字情绪识别 五.识别是否带了口罩 六.简易信息轰炸 七.识别图片中的文字 八.简单的小游戏 Python凭借其简洁的代码,赢得了许多开发者的喜爱.因此也就促使了更多开发者用Python开发新的模块,从而形成良性循环,Python可以凭借更加简短的代码实现许多有趣的操作.下面我们来看看,我们用不超过10行代码能实现些什么有趣的功能. 一.生成二维码 二维码又称二维条码,常见的二维码为QR Code,QR全称Quick Response,是一个

  • 20行Python代码实现一款永久免费PDF编辑工具

    目录 PyPDF2 删除PDF页 合并PDF 旋转 添加水印 加密 pdfminer PDF转TxT 总结 PDF是我们经常会接触到的一种文件格式,文献.文档...很多都是PDF格式.它以格式稳定的优势,使得我们在打印.分享.传输过程中能够最优的保持原有色彩和格式. PDF是以PostScript语言图像模型为基础的一种文档格式,它在格式的稳定性方面虽然具有很大优势.但是,在可编辑性方面却为使用者引入了另外一个困扰. 例如,在文档的分割.合并.剪切.转换.编辑等方面PDF就有些捉襟见肘了. Ad

  • 10 行 Python 代码教你自动发送短信(不想回复工作邮件妙招)

    最近工作上有个需求,当爬虫程序遇到异常的时候,需要通知相应的人员进行修复.如果是国外可能是通过邮件的方式来通知,但国内除了万年不变的 qq 邮箱,大部分人都不会去再申请其他的账号,qq 邮箱也是闲的蛋疼的时候才会瞄一眼.你还记得上次看邮箱的内容是什么时候吗? 所以在国内最好的通知方式是通过手机短信,今天就教大家利用 python 10 行代码实现短信发送. Twilio 短信代理服务已经有非常多成熟的方案,比如国内的阿里云.这次我介绍的是国外的一个代理商「Twilio」,使用邮箱注册即送 15

  • 500行Python代码打造刷脸考勤系统

    需求分析 "员工刷脸考勤"系统,采用Python语言开发,可以通过摄像头添加员工面部信息,这里就涉及到两个具体的个问题,一个是应该以什么样的数据来标识每一个员工的面部信息,二是持久化地保存这些信息到数据库中去.更细地,还涉及表的设计;另一个基本要求是通过摄像头识别员工面部信息来完成考勤,这个问题基本可以通过遍历数据库里的员工面部数据与当前摄像头里的员工面部数据的比对来实现,但有一个问题就是假如摄像头里有多张人脸改怎么处理.扩展要求是导出每日的考勤表,可以拆分为两个部分,一个是存储考勤信

随机推荐