<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      [python][flask] Flask 圖片上傳與下載例子(支持漂亮的拖拽上傳)



      1、效果預覽

      我們基于 Flask 官方指導工程,增加一個圖片拖拽上傳功能,效果如下:


      2、新增邏輯概覽

      我們在官方指導工程 https://github.com/pallets/flask/tree/2.1.1/examples/tutorial/flaskr 上進行增加代碼,改動如下:

      ?  flaskr git:(main) ? tree
      .
      ├── static
      │   ├── file
      │   │   ├── css
      │   │   │   └── upload.css           <-  增加圖片上傳的 CSS
      │   │   ├── img
      │   │   │   ├── 20220525004341_22.png
      │   │   │   └── 20220529231518_76.png
      │   │   └── js
      │   │       └── upload.js            <- 增加圖片上傳的 JS
      │   └── style.css
      ├── templates
      │   ├── auth
      │   │   ├── login.html
      │   │   └── register.html
      │   ├── base.html
      │   ├── blog
      │   │   ├── create.html
      │   │   ├── index.html
      │   │   └── update.html
      │   └── tuchuang                     <- 增加圖片上傳的 html
      │       └── upload.html
      ├── auth.py
      ├── blog.py
      ├── db.py
      ├── __init__.py
      ├── schema.sql
      └── tuchuang.py                      <- 增加圖床 python 藍圖
      
      9 directories, 18 files
      

      由于 flask 官方 Demo 基于藍圖設計,這給我們新增邏輯帶來了很大的方便。關于官方 Demo 的介紹,可以參考我的《Flask 入門(以一個博客后臺為例)


      3、tuchuang.py 邏輯介紹

      3.1 圖片上傳

      1)該接口采用 POST 方法,需要登錄;
      2)接著,檢查請求中是否有 'file' 關鍵詞,然后取出文件,判斷文件是否為空或是否合法;
      3)最后,將上傳的圖片保存(采用秒級別的時間戳+隨機數重命名);
      4)該接口在上傳圖片成功后,返回該圖片的鏈接;如果不成功,返回 upload.html 頁面;

      @bp.route('/', methods=['GET', 'POST'])
      @login_required
      def upload_file():
          if request.method == 'POST':
              # check if the post request has the file part
              if 'file' not in request.files:
                  flash('No file part')
                  return redirect(request.url)
              file = request.files['file']
              # If the user does not select a file, the browser submits an
              # empty file without a filename.
              if file.filename == '':
                  flash('No selected file')
                  return redirect(request.url)
              if file and allowed_file(file.filename):
                  # 獲取安全的文件名 正常文件名
                  filename = secure_filename(file.filename)
                  
                  # 生成隨機數
                  random_num = random.randint(0, 100)
                  # f.filename.rsplit('.', 1)[1] 獲取文件的后綴
                  filename = datetime.now().strftime("%Y%m%d%H%M%S") + "_" + str(random_num) + "." + filename.rsplit('.', 1)[1]
                  file_path = app.config['UPLOAD_FOLDER']    # basedir 代表獲取當前位置的絕對路徑
                  
                  # 如果文件夾不存在,就創建文件夾
                  if not os.path.exists(file_path):
      	            os.makedirs(file_path)
      	
                  file.save(os.path.join(file_path, filename))
                  return redirect(url_for('tuchuang.download_file', name=filename))
          return render_template("tuchuang/upload.html")
      

      3.2 圖片合法檢查

      上述代碼中有一個合法檢測的函數 allowed_file,用于檢查上傳圖片的后綴是否在允許列表:

      basedir = os.path.abspath(os.path.dirname(__file__))                 # 獲取當前文件所在目錄
      UPLOAD_FOLDER = basedir+'/static/file/img'                           # 計算圖片文件存放目錄
      ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'}     # 設置可上傳圖片后綴 
      
      app = Flask(__name__)
      app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
      bp = Blueprint("tuchuang", __name__, url_prefix="/tuchuang")
      
      def allowed_file(filename):                                          # 檢查上傳圖片是否在可上傳圖片允許列表
          return '.' in filename and \
                 filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
      

      3.3 圖片下載

      圖片下載比較簡單,就是調用 send_from_directory 函數,就能夠把 static 目錄下的對應文件發出:(我們一般把各種用于外面訪問的靜態圖片、JS、CSS 等放在 static 文件中)

      @bp.route('/download/<name>')
      def download_file(name):
          return send_from_directory(app.config["UPLOAD_FOLDER"], name)
      

      4、__init__.py 邏輯介紹

      由于我們采用藍圖設計,因此需要稍微修改下 __init__.py 文件,來將 tuchuang.py 加入:

      • MAX_CONTENT_LENGTH=16 * 1000 * 1000 上傳圖片大小限制
      • from flaskr import auth, blog, tuchuang
      • app.register_blueprint(tuchuang.bp) 將 tuchuang 加入藍圖
      • app.add_url_rule("/download/<name>", endpoint="download_file", build_only=True)

      5、upload.html 介紹

      5.1 upload Jinja 模板介紹

      • Jinja 引用外部 css:<link rel="stylesheet" href="{{ url_for('static', filename='file/css/upload.css') }}">
      • Jinja 引用外部 js:<script type="text/javascript" src="{{ url_for('static', filename='file/js/upload.js') }}"></script>
      • 該 Jinja 模板實現了兩種圖片上傳交互:
        • 普通版,采用 file select 框 + submit 按鈕,實現圖片上傳:
          <form method=post enctype=multipart/form-data>
              <input type=file name=file>
              <input type=submit value=Upload>
          </form>
          
        • 拖拽版(需要借助 JS,CSS),在 <div id="drop-area"> 內實現

      下面是 tuchuang/upload.html 完整代碼:

      <!doctype html>
      <link rel="stylesheet" href="{{ url_for('static', filename='file/css/upload.css') }}">
      <script type="text/javascript"  src="{{ url_for('static', filename='file/js/upload.js') }}"></script>
      <title>Upload new File</title>
      <h1>Upload new File</h1>
      <form method=post enctype=multipart/form-data>
          <input type=file name=file>
          <input type=submit value=Upload>
      </form>
      <div id="drop-area">
          <form class="my-form">
              <p>Upload multiple files with the file dialog or by dragging and dropping images onto the dashed region</p>
              <input type="file" id="fileElem" multiple accept="image/*" onchange="handleFiles(this.files)">
              <label class="button" for="fileElem">Select some files</label>
              <div id="gallery"></div>
              <progress id="progress-bar" max=100 value=0></progress>
          </form>
      </div>
      

      5.2 upload css 介紹(虛線框)

      下面是拖拽需要用到的 CSS,大家暫時瀏覽下,之后結合 JS 就明白了:

      ?  css git:(main) ? cat upload.css            
      #drop-area {
          border: 2px dashed #ccc;
          border-radius: 20px;
          width: 480px;
          font-family: sans-serif;
          margin: 100px auto;
          padding: 20px;
      }
      #drop-area.highlight {
          border-color: purple;
      }
      p {
          margin-top: 0;
      }
      .my-form {
          margin-bottom: 10px;
      }
      #gallery {
          margin-top: 10px;
      }
      #gallery img {
          width: 150px;
          margin-bottom: 10px;
          margin-right: 10px;
          vertical-align: middle;
      }
      .button {
          display: inline-block;
          padding: 10px;
          background: #ccc;
          cursor: pointer;
          border-radius: 5px;
          border: 1px solid #ccc;
      }
      .button:hover {
          background: #ddd;
      }
      #fileElem {
          display: none;
      }
      

      5.3 upload js 介紹(拖拽)

      5.3.1 JS 拖拽框架

      JS 代碼主要基于 window.onload + 拖拽事件實現,大致框架如下:

      ?  js git:(main) ? cat upload.js 
      window.onload=function(){
          var dropArea = document.getElementById('drop-area')
      
          // 阻止默認行為
          ;['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
              dropArea.addEventListener(eventName, preventDefaults, false)
          })
      
          function preventDefaults (e) {
              e.preventDefault()
              e.stopPropagation()
          }
      
          // 增加事件,鼠標拖入邊框高亮,拖出邊框變為原來樣子
          ;['dragenter', 'dragover'].forEach(eventName => {
              dropArea.addEventListener(eventName, highlight, false)
          })
      
          ;['dragleave', 'drop'].forEach(eventName => {
              dropArea.addEventListener(eventName, unhighlight, false)
          })
      
          function highlight(e) {
              dropArea.classList.add('highlight')
          }
      
          function unhighlight(e) {
              dropArea.classList.remove('highlight')
          }
      
          // 增加事件,鼠標放下,之后準備上傳圖片
          dropArea.addEventListener('drop', handleDrop, false)
      
          function handleDrop(e) {
          	// 之后準備上傳圖片
          }
      }
      

      window.onload() 方法用于在網頁加載完畢后立刻執行的操作,即當 HTML 文檔加載完畢后,立刻執行某個方法。

      為什么使用 window.onload()?

      因為 JavaScript 中的函數方法需要在 HTML 文檔渲染完成后才可以使用,如果沒有渲染完成,此時的 DOM 樹是不完整的,這樣在調用一些 JavaScript 代碼時就可能報出"undefined"錯誤。


      5.3.2 JS 圖片上傳
      function handleDrop(e) {
      	// 從拖拽放下事件中獲取拖拽的文件
          let dt = e.dataTransfer
          let files = dt.files
      
      	// 調用圖片處理函數,對圖片進行處理
          handleFiles(files)
      }
      
      function handleFiles(files) {
      	// 對于多個圖片,循環調用 uploadFile 函數,進行上傳
          ([...files]).forEach(uploadFile)
      }
      
      function uploadFile(file) {
      	// JS 合成表單,利用 POST 方法,實現上傳(部署在遠端時,要改下下面的 url)
          let url = 'http://127.0.0.1:5000/tuchuang/'
          let formData = new FormData()
      
          formData.append('file', file)
      
          fetch(url, {
              method: 'POST',
              body: formData
          })
              .then(progressDone) // <- Add `progressDone` call here
              .catch(() => { /* Error. Inform the user */ })
      }
      

      Fetch API 提供了一個 JavaScript接口,用于訪問和操縱HTTP管道的部分,例如請求和響應。它還提供了一個全局 fetch()方法,該方法提供了一種簡單,合理的方式來跨網絡異步獲取資源。詳細介紹參考《參考鏈接[8]》:

      • 1.進行 fetch 請求 參考;
      • 2.支持的請求參數參考;
      • 3.發送帶憑據的請求參考;
      • 4.上傳 JSON 數據參考;
      • 5.上傳文件參考;
      • 6.上傳多個文件參考;
      • 7.檢測請求是否成功參考;
      • 8.自定義請求對象參考;
      • 9.Headers參考;
      • 10.Guard參考;
      • 11.Response 對象參考;
      • 12.Body參考;
      • 13.特性檢測參考;

      該文章講的比較好,大家可以跳轉過去學習下~


      5.3.3 JS 圖片上傳進度條

      想要帶有進度條,我們需要修改下 handleFiles 函數:

      var filesDone = 0
      var filesToDo = 0
      var progressBar = document.getElementById('progress-bar')
      
      ...
      
      // 預覽
      function previewFile(file) {
          let reader = new FileReader()
          reader.readAsDataURL(file)
          reader.onloadend = function() {
              let img = document.createElement('img')
              img.src = reader.result
              document.getElementById('gallery').appendChild(img)
          }
      }
      
      // 進度條初始化,fileDone 置 0,filesToDo 置需要上傳圖片總數
      function initializeProgress(numfiles) {
          progressBar.value = 0
          filesDone = 0
          filesToDo = numfiles
      }
      
      // 注意,該函作為 fetch 的返回回調函數,意思是每次傳輸完成一個圖片,進度條進行相應變化
      function progressDone() {
          filesDone++
          progressBar.value = filesDone / filesToDo * 100
      }
      
      function handleFiles(files) {
          files = [...files]
          initializeProgress(files.length) 
          files.forEach(uploadFile)
          files.forEach(previewFile)
      }
      

      6、后記

      本文涉及到的源代碼在 GITHUB,后續我會基于該工程加入各種有意思的功能。
      此外,之前的兩篇文章列在下面,可能對您理解本文有幫助:


      參考鏈接

      [1]. 本文代碼 GITHUB
      [2]. 在HTML中引入CSS的幾種方式介紹
      [3]. python Flask中html模版中如何引用css,js等資源
      [4]. HTML引入JS的兩種方法
      [5]. 使用Flask引用HTML中的.js文件的靜態資源問題
      [6]. Flask 官方指導 Uploading Files
      [7]. JavaScript window.onload
      [8]. JavaScript使用 Fetch
      [9]. 本文 JS+CSS 參考



      : 這篇是在大家熟悉 flaskr 的指導項目之后,實現一個圖片上傳和下載的案例...

      如果覺得不錯,幫忙點個支持哈~

      posted @ 2022-05-31 09:19  beautifulzzzz  閱讀(2847)  評論(1)    收藏  舉報
      主站蜘蛛池模板: 99精品国产在热久久婷婷| 久久毛片少妇高潮| 日韩伦人妻无码| 18禁无遮挡啪啪无码网站破解版| 亚洲国产码专区在线观看| av深夜免费在线观看| 亚洲情A成黄在线观看动漫尤物| 国产美女69视频免费观看| 午夜福利宅福利国产精品| 人妻精品久久久无码区色视| av色欲无码人妻中文字幕| 中文字幕丰满伦子无码ab| 在线播放深夜精品三级| 久热re这里精品视频在线6| 日本不卡的一区二区三区| 噜噜综合亚洲av中文无码| 国产无套白浆一区二区| 亚洲乱码中文字幕小综合| 亚洲欧美人成电影在线观看| 伊人久久大香线焦av综合影院| 人人做人人澡人人人爽| 亚洲av二区伊人久久| 国产日韩在线亚洲色视频| 国产成人午夜福利在线播放| 欧美丰满熟妇vaideos| 中文字幕在线国产精品| 色琪琪丁香婷婷综合久久| 国精品午夜福利视频不卡| 亚洲精品国男人在线视频| 国产精品一区二区无线| 少妇高潮潮喷到猛进猛出小说| 久久精品国产亚洲不AV麻豆| 农村欧美丰满熟妇xxxx| 久热色视频精品在线观看| 国产一区二区三区禁18| 91久久夜色精品国产网站| 久久午夜私人影院| 亚洲无人区一区二区三区| 女人下边被添全过视频的网址| 久青草国产综合视频在线| 国产不卡在线一区二区|