FastAPI - File Uploads from HTML Forms / Dropzone.js integration

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
let's learn how to upload a file using fast API we're going to start in this video by defining some code to upload a fail to fast API using an HTML form and then we're going to learn how to handle the submission of that fail on our fast API backend endpoint and as well as a single file we're also going to learn how to handle the upload of multiple files in a single fast API endpoint after that we're going to dive into dropzone.js which is a JavaScript library that you can use to upload multiple files using Ajax requests we're going to see how we can wire up fast API on the back end to handle those submissions and in the next video we'll see how we can handle these submissions using a library such as react.js on the front end but for now let's get started now we're going to be following along with this page of the fast API documentation to begin with and this page tells us some information about how we can handle requests that are coming into our fast API application when those requests contain fails so on the right hand side at the sidebar here I'm going to click this link file parameters with upload file and I'll leave the link to this below the value now as you can see below there are two ways to Define these endpoints I'm going to make this a little bit bigger so we can see that in the first of these two functions we have an endpoint that has a fail parameter and the type of that file is annotated which comes from Python's standard libraries typing module and the actual type underlying that is bytes raw bytes that are coming into the fast API endpoint and it's annotated with this fail object that comes from Fast API now as it says below here using the upload file type that has several advantages over the raw bytes and this is the technique that's used in the second endpoint that has the same parameter of fail but it's tape annotated here with the upload file type now what are the advantages of upload fail let's scroll down first of all we don't have to use this fail object as a default value for the parameter and also more importantly it uses a spilled file and this means that the file is stored in memory up to a maximum size limit and then after passing that limit it is then stored onto the disk so using upload file will work well for large files such as images and videos and large binaries and that's because it's not going to try and store the entire file in memory instead it's going to Spill the fail to a desk after a certain maximum limit is reached so you want to use upload fail whenever you're dealing with potentially large files and some other benefits down here you can see that we can get metadata from the uploaded file and that it also has a fail Lake async interface so let's go down again I'm going to see that upload file has some attributes that we're going to use for example the file name of the uploaded file will contain the original file name from the client and we can also access the content type of the uploaded file for example a JPEG file and as well as that we can access an attribute called fail which is actually the underlying spilled temporary file in Python an upload file also has some async methods that follow the file interface in Python so what I'm going to do to start with is I'm going to scroll back to the top of this page because it contains less important information here to receive uploaded files and fast API we need to install this Library called python multipot so I'm going to copy the pep install command and I'm going to go to vs code and in the terminal where I've got a virtual environment activated I'm going to paste in that pip install command and as you can see it's already installed on my computer but you will need to install that if you're going to receive uploaded files in fast API now within this vs code directory that I've got open I also have a main.pi file that Imports the fast API object and then instantiates it and stores it in a variable called app so we're now going to use this file to Define some roots that can handle uploading files to fast API so I'm going to start by doing at the top as well as importing fast API I'm also going to import that type called upload fail that we've seen in the documentation and then below the fast API app object let's define a post route here and we'll give that an endpoint of upload fail and below that will Define the actual function for this route and we're going to make that an async function called create upload file now that is going to take a parameter called file and that's going to have a type of upload file and what we're going to do for now I'm going to go back to the fast API documentation and go back to that page that we were looking at and I'm just going to return the file name when it's uploaded to that particular endpoint so let's go back to vs code and the return statement is simply going to return the uploaded files name back to the client what I'm going to do now is create an HTML file within this directory and we're going to Define an HTML form that contains a file field so on the left hand side I'm going to create a new file here and let's just call that index.html and within this file I'm going to paste some boilerplate HTML and that's just an HTML tag that contains a head and our body what we're going to do next in this video within the body tag is we're going to define a form element and we're going to define a field within that to upload our file so let's start by defining the forms method which is going to be a post request and that's going to be a post request coming into this fast API endpoint that we've just defined and we need to tell the form to send the post request to this end Point here which is going to be localhost 8000 slash upload file so let's go back to the HTML file and we can Define the action attribute here and set it equal to that end point there and that means that when the form is actually submitted it's going to send the post request data to that particular URL and that will then be handled on the back end using fast API let's go back to the form and there's one other attribute that we're going to Define on this formula I'm going to do it on our new line here and that's the ink type which stands for encoding type now when you submit a form that contains files you need to set the encoding type to multi-part slash form data and that means that the data that's in the form is going to be submitted to the back end using a form data object we're going to see more about that in the next video where we use react to actually submit a phone but just know that you definitely need to include this encoding type on a form element when you're submitting a form that contains files now within the form we're going to Define an input element and that is of type equals fail here and we need to get the less input a name so that the backend knows what to look for in our case let's call it file underscore upload and then we can close off the input tag and below the input we're going to Define our submit button so that we can actually submit the form and then that will send the data to the back end now there's something important to highlight here and that's the name of this input element it's got a name of file upload and you need to match that on your back end for the parameter to the function we've currently got a parameter of file so we're going to need to change that to match the name that's coming through from the HTML form so let's change it to file upload and then we can use the fail uploads file name when we return that dictionary response so let's now run the server and we're going to try and actually submit this HTML form and see what happens on our fast API root so what I'm going to do is install the yuvicorn server here and that's an asynchronous server that you can use with fast API once that's installed we can run a command you have a con and we're going to reference the main file and the app object within that file and we can use the dash dash reload flag so that whenever we change any of the code it's going to restart the server once that server is running we are going to open this HTML file where we've defined the form and I'm going to go to the browser and this is the page here we have an input of type fail on the left hand side and a button to submit the form on the right so a very basic user interface but what we're going to do is we're going to select a file now and within the directory I have this subdirectory called source files and I'm going to select for example this file here that contains a picture of a dog and then we're going to submit that to the server and you can see that we get back some Json data we have a key of file name and the value is the name of the file and that matches what we have on the back end for main.pi we're returning that key and we're referencing the name of the file that was uploaded you can also see at the bottom on the terminal that a post request was made to the slash upload file endpoint and that will come in to this endpoint and Trigger this function which is returning that data so that's good we're able to accept the fail on the back end let's now try and save it to the file system when it comes into this root so what we're going to do is Define a directory where we want to store the uploaded files on the server so to do that I'm going to import From pathlib the Path object once we've got that import I'm going to set our variable called upload directory and that's going to be equal to the current directory which you can get just by instantiating a path object and from the current directory we'll reference a subdirectory which we'll call uploads so I'm going to do is create that directory called uploads within the root of this project and that is where the uploaded files are going to be stored on the servers file system and of course in a real application you can set this to anywhere you want on your file system or you can set it to an S3 bucket or anywhere on the cloud but for the purposes of this video Let's just store things within the root directory now in order to store the content of the files we're going to need to actually read that file within this function here so let's start by writing some new code here we're going to read the file that's been uploaded so let's Define a variable called data and we can use the file uploads reads method in order to do that and that is an asynchronous function so we can use the await keyword and that's going to wait on that being read before continuing with the function and if you're using the awake keyword to read this file remember you need to have your function be async ready so make sure you have the async keyword below that I'm going to create a variable called save to and that's going to be equal to the upload directory which is this uploads directory that we have here and below that we're going to just save the file with the file name of whatever was uploaded from the client so this is the location and the file name of where we want to store the content that's been uploaded so let's open that particular location with a with open statement in Python we'll reference that location called save to and we want to write and we want to specify we were rating baits here and we can do that by opening this file object with the mode of write bytes as it says here and we can reference the open file and we'll just call that if once we have that file opened we can call the fail.rate function and what we're going to do is write the data that we've read on line 10. to that particular location on the file system and that's the changes we need to actually take the uploaded file read it into memory and then save it to that location on line 11. so let's try this out again we're going to go back to our HTML form here and if we choose another file from that directory let's try this Json sample if we submit that to the back end we get back the same response but let's now go to vs code and you can see on the left hand side within this uploads directory that we now have the file that has been uploaded called jsonsample.pdf that's now stored in that directory and it's now on our server on the server's file system so just to reiterate what we're doing on line 10 we read the data from the file that's been uploaded on line 11 we Define a location to save that data to and then on line 12 we open a file at that location with a mode of rate bytes and then we write that data to that location so that's how to take a file that's been uploaded from an HTML form and then store it on the file system on a server that's using fast API and we can also Define optional points I'm going to go back to the documentation on the right hand side we have this section here for optional file upload and this can be done using standard type annotations for example using the upload fail object we can define a union type with the second type equal to none and the default value is set to none as well in case a file has not been uploaded so if you have an endpoint and you don't require a file to be uploaded this is one way to do that now on the right hand side again here we have a section for multiple failure modes let's now learn how to upload multiple files to a single fast API function and it's very simple to annotate this we just declare a list of bytes on a list of upload file types and you can see that down here in this function we have a parameter of files and that is a list of upload file objects so we're going to use this technique in that function of defining a list of upload file types let's go back to vs code and I'm going to change the parameter here from fail upload to fail uploads and then we'll make the type for that list of these upload fail objects and if you're using a version of python below 3.9 you will need to annotate this slightly differently if we go back to the documentation this tab here on 3.6 plus you can see that you actually need to import the list type from the typing module it was only in Python 3.9 and above that you can use the list as a type as well as a built-in function so let's go back to vs code and we're going to keep this code largely the same but what we're going to do is iterate over each fail upload that is in this list of file uploads so let's go into the function here and Define our for loop we're going to see for fail upload in fail uploads and we can keep the rest of this code largely the same we're going to read the particular file that we're iterating over and we're going to save it to that directory on the file system and we can now do this for a list of files by iterating over each one one at a time and saving the content to the file system and the only other thing we need to do is change the return statement after the for Loop I'm going to paste in a bit of code here and instead of returning a single file name we're now using a less comprehension to get the file name of every file that's been uploaded and returning that as a list so we're going to test this out in a second but we need to make a couple of changes to the index.html template that we're using firstly we need to change file upload to fail uploads and remember that's because the name attribute of this input element must match the parameter name that we're defining on the fast API function so that will need to be changed to fail upwards and because we're wanting to allow multiple fail uploads we can use the multiple attribute here and that will tell the browser that the file field can accept multiple files for that particular field so we can now save these files and go back to the browser and what I'm going to do in this case is choose all five of these files and we're going to open all five of them and you can see that because we have the multiple attribute we have all five of these files for this particular field before we submit that I'm going to go back to vs code and I'm going to clear out this file from the uploads directory and then we can try submitting this to see if all five of these end up in that particular directory so let's submit the form and we get back a list of file names here as we expect from the fast API function and if we go back to vs code you can see within the uploads directory we have all five of these files that have been uploaded and saved to that directory so that's how we can upload multiple files using a single file field and the front end and accept those on the back end and save them to the file system and what we're going to do to finish this video is learn how to integrate this with Drop Zone JS I'm going to go back to the browser and go to the documentation for DropZone and I'm actually going to open the tab for the home page here and you can see that drops on it's a simple JavaScript library it helps you add fail drag and drop operations and functionality to your web forms and it's one of the most popular drag and drop libraries on the web so what we're going to do is we're going to learn how to install this and then use it to upload files using Ajax requests which is slightly different to submitting the form as we've been doing so far on this page here where we submit the entire form and then we get a Reload of the page with the response from the server what we're going to do with the DropZone is submit these files using an Ajax request now drop zone is an external Javascript Library so we're going to copy these script and Link tags and we're going to import them into our template that we've got within this index.html file so let's go back to that and within the head tag I'm going to paste these Imports in and this contains the JavaScript and the CSS for the dropzone.js package and once we've got these installed let's go back to the documentation and on the setup section of the sidebar we're going to click the declarative setup and this section tells us how we can create a drop zone upload with HTML attributes so you can see here we have a form element and it has an action that will tell the form where to send the data and this has a class of drop zone and an ID of my awesome drop zone and what we're going to do is we're going to go back to vs code and I'm going to replace this form element here with the Drop Zone form declaration and I'm replacing the action with the action that we have sending the data to to our fast API endpoint and I'm going to remove this ink type here as well so we have a form it has the same action but now we have a class of drop zone and we have an ID of my awesome drop zone and that's actually all we need here we don't need the input of type fail or the submit button because Drop Zone itself is going to handle submitting all that data to the server and it's going to use Ajax requests to do that so let's go to our page and we're going to see how this looks like at the moment we're not completed the setup but if we go back here you can see that we have some kind of new field on this page this is the Drop Zone element but it's not been instantiated properly we're going to learn how to do that now if we go back to the documentation let's go to this page on the imperative setup and you can see in the code below here that we create a new Drop Zone object and the first argument to that is the selector of the HTML element that we want to add drops onto and the second parameter is optional but that contains some options that you can then apply to your Drop Zone element that can change the way it behaves and other things such as the state tail of the object so we're going to use this technique here I'm going to copy this code and we're going to go back to vs code and within the body I'm going to define a script tag here and remember to close that off as well and I'm going to paste in the code that we copied so we're instantiating a new Drop Zone object and remember the first parameter here that's the element we want to actually apply this to so we're going to remove that and we're going to reference my awesome Drop Zone which is the ID of this form element and I'm also going to remove this URL option here we don't need to tell Drop Zone where to submit the data to because we have an action attribute directly on the form itself that will tell the form where the location is that it should send its data to now we are going to set one option here and that's going to be an option called param name and we're going to set that equal to fail underscore uploads and the reason for this is because if we go back to main.pi this is the actual name that we're expecting from the front end it's called fail uploads and we are using that as an argument or a parameter to our fast API function so that needs to be the name of the data that we're sending for these file fields from the front end so we're going to make sure we call it fail uploads by overriding this paramn name if we go back to the Drop Zone documentation for the declarative section you can see this information here if you want a name other than fail you can configure Drop Zone with the option of param name and that's what we've done because by default it will have a name of file so let's now test this out and we're going to go back to this page you can see that when we refresh the page we now have a different UI because we've instantiated the Drop Zone element and we can drag and drop files into this or we can click it to get the file browser and I'm going to select all five of these again and you can see that it's uploading each of them but the server is responding with a zero code and the objects are not actually being uploaded if we go back to vs code and look at the terminal here you can see we have a 405 method not allowed now the problem is on the browser we're just loading this HTML file onto the page and we're trying to upload to a different origin which is our fast API server that is running at localhost and Port 8000. what we need to do in order to make this work because it's an Ajax request that's coming from a different origin we need to add cores middleware to our fast API application and if we do that we can then accept the files coming from a different origin using the Ajax request so I'm going to load up some documentation from Fast API here and this is from the page on course which I'll link below the video and you can see what the definition of an origin is from this page It's a combination of the protocol HTTP or https the domain which can be basically anything including localhost and also the port and you can see that these are all different Origins here for example using HTTP and localhost and then using https and localhost it's a different origin and if you have two processes on localhost with different port numbers these are going to be different Origins as well so the problem here is that we have two pages or two processes that are running on different Origins and our server is therefore going to flag this and we're not going to be able to upload these files from a different origin now in order to resolve this we can go to the right hand side and we can use the core's middleware that's built into fast API and the steps for using that we can import it and then we can create a list of allowed Origins as strings and finally we can add this as a middleware to our fast API application so let's scroll down here and I'm going to copy the import statement and we're going to go back to vs code to the main.pi file and at the top here I'm going to import the cores middleware what we need to do after that if we go back to the documentation we can define a list of allowed Origins and then we can set up this middleware and add it to the app object so what I'm going to do is copy this code here where we're adding the middleware and I'm going to go back to vs code and underneath this app object I'm going to paste that in and for Simplicity the allowed Origins I'm just going to set that to a list where we have this star character that's a wild card that tells the server that any origin is allowed that's not recommended for production so don't do that in a real system you can Define you your allowed Origins explicitly using this list but we're just going to allow the uploads to come from any origin once we've done that we can go back to our page here and I'm going to try re-uploading these files using the Dropbox element if we take all of these files you can see that they are now all uploaded we have the success Tech message appearing and if we go back to the server you can see in the uploads directory we have these files now I'm not sure if these were already here so let's delete these and we can try this again and we're going to select let's just say the first three of these files and let's now go back to the server and you can see we have the three files in the directory here and you can see in the terminal the DropZone is actually sending three post requests to this back end and it's actually sending one file at a time so we don't need to annotate this with a list of upload files instead we can just create the normal fail upload parameter that is equal to an upload file and we can get rid of these statements here and finally within the return statement we can just say failupload dot fail name here and the last thing we need to do remember is match the name of the parameter with what we have as a param name when we create a drop zone object here so let's make that file upload now we can go back to the browser and test this out if we refresh the page and select the top two of these files and try and upload them you can see we get a successful upload and this time the files have come through to the back end again they're coming through one at a time as you can see at the bottom here and each one of them is treated as a separate request so that's what DropZone does it takes a list of files that you've dragged and dropped or selected in that drop zone element and it sends an asynchronous request an Ajax request to the fast API server and it's going to send a new Ajax request for each file to the fast API endpoint which will then save the file to the file system as you can see on lines 19 to 22 and because the Ajax request is sent from a different origin on the browser we need to add this middleware the course middleware to the app object and we can specify some allowed Origins and methods to that middleware so that's all for this video we've seen how to take a sale that's been uploaded from the front end or multiple files from the front end and then store those files on the file system using a fast API endpoint we've also seen how we can use dropzone.js to send Ajax requests and how we can add a course middleware to our fast API app object in order to allow fast API to handle fail uploads from a different origin that are coming from an Ajax request and if you want to extend this example because we have async functions in fast API what you could do is you could use this Library here it's called AIO files and this allows you to use async IO when you're reading and opening files and other operations on files and that can help you in some situations perform actions much more efficiently with files you can look into that and you can use this library with fast API and that's because fast API works natively with async IO and async functions in Python so that's all for this video thank you for watching if you've enjoyed the video please like And subscribe to the channel and we'll see you in the next video
Info
Channel: BugBytes
Views: 5,239
Rating: undefined out of 5
Keywords:
Id: FFZdw7pn8OM
Channel Id: undefined
Length: 23min 55sec (1435 seconds)
Published: Mon May 01 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.