Follow these instructions to create your aws user and bucket, and obtain your credentials (stop after the Create your AWS User and Bucket section). You will need these credentials in subsequent steps to set up your environment.
You will also need to set up your bucket so that files can be publicly accessed—follow these instructions, again stopping after you finish the On AWS S3 Console section.
Finally, use pipenv to install the boto3
library in your project folder.
Put the name of your bucket, along with the Access Key ID and your Secret Access Key your .env
file. Make sure you include your .env
in your .gitignore
. You really don't want to push this information to github.
Create a file for AWS upload functionality. You will need to import boto3
and botocore
to implement your s3 functionality. You will also have to get your S3 values from the environment
Your S3 bucket cannot have two files with the same filename—if you upload two files with the same name one will get overwritten. We can avoid issue that by generating unique names every time we upload a file.
We can generate unique filenames using a UUID, and, specifically the uuid
module in Python. We can also limit the types of files users can upload in this step.
Here are the helper functions we'll use to get filenames.
Now let's write the function that we'll need to actually upload the file—and return the url if we're successful.
So, at this point, our file looks like this:
For the purposes of this tutorial, let's assume we have an Image model in our database with a column for the image url and a column for the id of the user who uploaded the image. After we've successfully uploaded the image to S3, we can store the returned URL in our database.
Here is a simple example of a component for users to upload images. You will undoubtedly need to modify this for your usage, but make sure that the name of the field you attach to your FormData
object matches what you are looking for on the backend end (i.e. the name in formData.append("<some name>", image);
should match image = request.files["<some name>"]
).
Note that you must NOT set the Content-Type
header on your request. If you leave the Content-Type
field blank, the Content-Type
will be generated and set correctly by your browser (check it out in the network tab!). If you include Content-Type
, your request will be missing information and your Flask backend will be unable to locate the attached files.
Check out this repo to see this code in context.
Inspired by this boto3 tutorial, as well as this tutorial that uses Express.