Article directory
-
- ?Foreword
-
- Technology stack selection
- ?Front-end page construction
-
- Adjust request content-type to pass formData
- ?Backend interface implementation
-
- swagger document test interface
- ? Front-end and back-end implementation effects
-
- Upload a single file
- Upload directory files
- ?Summarize
- ?Finish
?Foreword
Hello everyone, I am yma16. This article shares about vue3 + fastapi to implement selected directory files and upload them to the specified location on the server.
Vue3 series related articles:
Front-end vue2 and vue3 remove the “#” number in url routing – nginx configuration
csdn new star plan vue3 + ts + antd track – using inscode to build vue3(ts) + antd front-end template
Understand vite_vue3 initialization project to packaging
python_selenuim obtains the city where the csdn new star track player is located and displays it on the echarts map
Python series of articles:
python crawler_basic data types
python crawler_use of functions
Use of python crawler_requests
python crawler_selenuim visualization quality score
python crawler_django + vue3 visual csdn user quality score
python crawler_regular expression to obtain weather forecast and display it with echarts line chart
Python crawler_requests obtains the subtitles of the bilibili Blacksmithing Village series and uses word segmentation to divide the visual word cloud diagram for display
python crawler_selenuim log in to personal markdown blog site
Python crawler_requests gets the Minion expression and saves it to a folder
python_selenuim obtains the city where the csdn new star track player is located and displays it on the echarts map
Technology stack selection
Front-end: vue3 + ts + antd
Backend: python + fastapi
vue3 advantages
Vue3 has the following advantages compared to Vue2:
-
Faster rendering speed: Vue3 can achieve faster rendering speed by redesigning the responsive system and virtual DOM. In terms of memory usage and performance, Vue3 is more efficient than Vue2.
-
Better TypeScript support: Vue3 better supports TypeScript. The use of TypeScript in Vue3 is more direct, formal and stable, and type derivation is more accurate.
-
Better component development: Vue3 makes it easier to write components and separate templates, scripts and styles, making the code more readable and maintainable.
-
Better development experience: Vue3 adds many new features, such as Composition API, Teleport, Suspense, etc. These features make the development process simpler, more convenient and more flexible.
-
More ecological support: With the advent of Vue3, more and more plug-ins and libraries have begun to support Vue3, such as Vue Router, Vuex, etc. The development of these ecological tools will contribute to the rapid development of Vue3.
fastapi advantages
The advantages of FastAPI are mainly reflected in the following aspects:
-
High performance: FastAPI uses an asynchronous programming model and asynchronous processing of requests based on event loops, which can easily handle a large number of concurrent requests and improve server performance.
-
Easy-to-use API development: FastAPI can automatically generate API documentation, so developers can use it to quickly write APIs without spending a lot of time writing documentation.
-
High reliability: FastAPI automatically performs type checking, which can avoid runtime errors caused by type errors and improve the stability of the API.
-
Supports native Python syntax: FastAPI can use Python native syntax to write code without having to learn a new language, making it easier to use the Python ecosystem.
-
Compatible with multiple front-end frameworks: FastAPI can be used with multiple front-end frameworks, including React, Angular, Vue.js, etc., providing greater development freedom.
-
Extensive community support: The FastAPI community is very active, has a large number of developers and users, and provides a wealth of resources and support.
?Front-end page construction
layout:
upper and lower structure
Above is the directory selection
Below is the folder selection
The implementation effect diagram is as follows
vue3 syntax sugar code implementation
<script lang="ts" setup> import {<!-- --> ref,reactive,computed } from 'vue'; import {<!-- --> InboxOutlined } from '@ant-design/icons-vue'; import {<!-- --> message } from 'ant-design-vue'; import {<!-- --> uploadFile,uploadUrl } from "../../service/gpt/index"; import {<!-- --> UploadOutlined } from '@ant-design/icons-vue'; const state:any=reactive({<!-- --> fileList:[], loading:false, text:'', dirList:[], dirPath:'', customFile:null, activeKey:'1', movieUrl:'' }); const upUrl=async ()=>{<!-- --> state.loading=true try{<!-- --> const res=await uploadUrl({<!-- --> url:state.movieUrl }) console.log('res',res) } catch (e) {<!-- --> message.error(JSON.stringify(e)) } finally {<!-- --> setTimeout(()=>{<!-- --> state.loading=false },200) } } const remove=(e:any)=> {<!-- --> console.log('drop file',e); state.fileList=[] } const removeDir=(e:any)=>{<!-- --> state.dirList=state.dirList.filter((file:any)=>file.uid!==e.uid) } const customRequesHandle=(e:any)=>{<!-- --> console.log(e,'custom') } const beforeUpload = (file:any) => {<!-- --> console.log('file before',file) state.fileList=[file] return false; }; const beforeUploadDir = (file:any) => {<!-- --> state.dirList.push(file) return false; }; const uploadSingleFile= async ()=>{<!-- --> state.loading=true console.log(typeof state.fileList[0],'file type') try{<!-- --> const formData=new FormData(); formData.append('file',state.fileList[0]) const res=await uploadFile(formData) console.log('res',res) }catch (e) {<!-- --> message.error(JSON.stringify(e)) } finally {<!-- --> setTimeout(()=>{<!-- --> state.loading=false },200) } } const upBtnDisabled=computed(()=>{<!-- --> return state.fileList.length===0 }) const change=(e:any)=>{<!-- --> console.log('change e',e) } const upDir=async ()=>{<!-- --> if(state.dirList.length===0){<!-- --> return message.warning('Please select a folder!') } state.loading=true const paramsData:any={<!-- --> dirList:state.dirList, dirPath:state.dirPath, } try{<!-- --> state.dirList.forEach(async (file:any)=>{<!-- --> try{<!-- --> const formData=new FormData(); formData.append('file',file) const res=await uploadFile(formData) console.log('res',res) }catch(r){<!-- --> message.error(JSON.stringify(r)) } }) }catch (e) {<!-- --> message.error(JSON.stringify(e)) } finally {<!-- --> setTimeout(()=>{<!-- --> state.loading=false },200) } } const previewDirFile=async (file:any)=>{<!-- --> return new Promise(resolve=>resolve(false)) } </script> <template> <div> <a-spin :spinning="state.loading" tip="upload..."> <div class="header-tools"> </div> <a-tabs v-model:activeKey="state.activeKey"> <a-tab-pane key="1" tab="Upload files"> <div> Upload folder <div style="margin: 5px;border: 1px dotted #1890ff;padding: 20px"> <div style="margin: 10px 0;max-height: 200px;overflow: auto"> <a-upload :before-upload="beforeUploadDir" v-model:file-list="state.dirList" list-type="picture" @remove="removeDir" directory> <a-button> <upload-outlined></upload-outlined> Upload folder </a-button> </a-upload> <div> </div> </div> <div style="margin:10px 0"> <a-button type="primary" block @click="upDir" :disabled="state.dirList.length===0" >Click to start parsing the folder</a-button> </div> </div> Upload leaflet file <div style="margin: 5px;border: 1px dotted #1890ff;padding: 20px"> <div> <a-upload-dragger :file-list="state.fileList" list-type="picture" :multiple="false" :before-upload="beforeUpload" @remove="remove" @change="change" > <p class="ant-upload-drag-icon"> <inbox-outlined></inbox-outlined> </p> <p class="ant-upload-text">Click to upload or drag and drop here</p> <p class="ant-upload-hint"> Select a document </p> </a-upload-dragger> </div> <div style="margin:10px 0"> <a-button type="primary" block @click="uploadSingleFile" :disabled="upBtnDisabled">Click to start uploading files</a-button> </div> </div> </div> </a-tab-pane> </a-tabs> </a-spin> </div> </template> <style> .header-tools{<!-- --> text-align: center; font-size: 24px; font-weight: bold; } .content-box{<!-- --> } .des{<!-- --> margin:20px 0; } </style>
Adjust request content-type to pass formData
axios package
import axios from "axios"; //Instance const createInstance = (baseURL:string)=>{<!-- --> return axios.create({<!-- --> baseURL:baseURL, timeout: 10000, headers: {<!-- -->'X-Custom-Header': 'yma16'} }) }; // @ts-ignore const http:any=createInstance(''); //Add request interceptor http.interceptors.request.use(function (config:any) {<!-- --> //What to do before sending the request return config; }, function (error:any) {<!-- --> //What to do with request errors return Promise.reject(error); }); //Add response interceptor http.interceptors.response.use(function (response:any) {<!-- --> // Status codes within the 2xx range will trigger this function. //Do something with the response data return response; }, function (error:any) {<!-- --> // Status codes outside the 2xx range will trigger this function. // Do something with the response error return Promise.reject(error); }); // File Upload const createUploadInstance = (baseURL:string)=>{<!-- --> return axios.create({<!-- --> baseURL:baseURL, timeout: 10000, headers: {<!-- -->"Content-Type": "multipart/form-data"} }) }; // @ts-ignore const uploadHttp:any=createUploadInstance(''); //Add request interceptor uploadHttp.interceptors.request.use(function (config:any) {<!-- --> //What to do before sending the request return config; }, function (error:any) {<!-- --> //What to do with request errors return Promise.reject(error); }); //Add response interceptor uploadHttp.interceptors.response.use(function (response:any) {<!-- --> // Status codes within the 2xx range will trigger this function. //Do something with the response data return response; }, function (error:any) {<!-- --> // Status codes outside the 2xx range will trigger this function. // Do something with the response error return Promise.reject(error); }); export {<!-- -->http,uploadHttp};
Service docking backend
import {<!-- -->uploadHttp} from "../../http/index"; export const uploadFile: any = (formData: any) => {<!-- --> return uploadHttp.post("/api/uploadFile/action", formData); };
?Backend interface implementation
Installation Environment
pip install uvicorn pip install fastapi pip install python-multipart
Upload a single file interface implementation:
from fastapi import FastAPI, status, File, Form, UploadFile from fastapi import FastAPI, status, File, Form, UploadFile from fastapi.middleware.cors import CORSMiddleware import os app = FastAPI() # Cross-domain configuration origins = [ "http://localhost:3000", ] app.add_middleware( CORSMiddleware, allow_origins=origins, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) @app.get("/api") async def root(): return {<!-- -->"data": "fast api!"} # upload files @app.post("/api/uploadFile/action") async def create_file( file:UploadFile ): writeBytes('./media',file) return {<!-- --> 'code':200, "msg":'success' } #Write file to dirs directory file def writeBytes(dirs,file): bytesFile=file.file.read() filename=file.filename if not os.path.exists(dirs): os.makedirs(dirs) with open(dirs + '/' + filename, "wb") as f: f.write(bytesFile)
uvicorn runs fastapi
uvicorn server.main:app --reload --port 7777
swagger document test interface
swagger document address:
http://ip:port/docs
Upload successful!
? Front-end and back-end implementation effects
Upload a single file
Upload directory files
Interface implementation for uploading directory files:
- file is a binary file
- dir is the directory name
- name is the complete file name
# Upload directory files @app.post("/api/uploadDirFile/action") async def uploadDirFile( file:UploadFile, dir:str=Form(), name:str=Form() ): print(dir,'dir_____________') writeBytes('./media/' + dir,name,file) return {<!-- --> 'code':200, "msg":'success' } #Write binary data to directory file def writeBytes(dirs,name,file): bytesFile=file.file.read() filename=name if not os.path.exists(dirs): os.makedirs(dirs) with open(dirs + '/' + filename, "wb") as f: f.write(bytesFile)
?Summary
Notes on file upload
front end:
- Request header configuration
headers: {"Content-Type": "multipart/form-data"}
- Parameter passing uses
new FormData()
rear end:
- Accept parameters using Uploadfile format
- Parse file content name including type and write file in format
multipart/form-data
multipart/form-data is a common HTTP request method, usually used to upload files or large amounts of data. It divides the requested data into multiple parts. Each part is separated by a boundary delimiter. Each part contains a header and a content body. The header describes the attributes of the part, such as data type and data encoding. wait. In the HTTP message body, each part must start with “–boundary\r\
” and end with “–boundary–\r\
”, that is, add an extra “–” mark at the end. When the client uses this method to request, it needs to explicitly specify that the Content-Type in the request header is multipart/form-data. After the server receives the request, it needs to parse out the request data in each part.
?End
This article ends here. If there are any errors or shortcomings, please point them out!
Likes are the motivation for my creation!
Collection is the direction of my efforts!
Comments are the wealth of my progress!
Thank you for reading!