Django Media Files - Handling User Uploads in Django Forms & Models

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this video we're going to dive into media files in Django and we're going to show how users can upload files to our Django server firstly we're going to learn how to create file fields and image views in our Django model classes and how these can track where images are stored by storing a path in the database we're then going to create a form that has an input field that allows the user to upload a file to the server and we're going to display that in a Django template after that we're going to show a list view that will list out all of the assets that have been uploaded and will also show how Django serves fails during development finally at the end of the video we're going to show how to delete these records from the database and also delete the associated files from our media directory so let's get started now here's a section of Django's documentation that I'll link just below the video we have a page on managing files and it describes how djangles fail access apis work and as it says here Django by default will store files locally using two settings one of them is the media root and the other one is the media URL so by D default files that are uploaded by users are going to be stored locally on a file system on your server but you can change that and have different storage backends for example Amazon S3 or Azure blob containers in this video we're just going to focus on local file systems later on we'll show other techniques now as well as these two settings that determine where files end up on your server or elsewhere we also have two fields that can be used in Django model classes and these two Fields come shipped with Django they are the fail fields and the image fields and obviously the image field is a specific type of fail field that is for images and under the hood it uses the python pillow library in order to determine features like the width and the height of that image but there's a generic fail field as you can see on this model here as well and that can take any kind of fail and we're going to see in this video how we can use an image field in a future video we're going to show how to use a fail field and we're going to restrict the types of files that can be uploaded in that video but for now we're going to focus on an image field so let's get started I've got our project open here on V es code this is a very basic Django setup and you can see here we have a very simple view that is serving this template called index.html and if we go to that template you can see that it's simply an H1 tag that says welcome and we can see in the browser what this looks like it just says welcome at the top here so we're going to change this template up and we're going to add a form later on that allows users to upload files so let's go back to vs code now this template extends a base template that's in the same directory so let's have a look at that and we can see we've got a script being loaded in that loads Tailwind CSS and we're going to use Tailwind for very basic styling in this video now what I'm going to do to start with is we're going to go to the settings.pi file that's part of the Django project and I'm going to scroll down here and we're going to add a couple of settings right at the bottom of this it doesn't matter where you add them but what I'm going to add is something called a media directory and that's going to be equal to the base directory which is at the top level of our project and then a subdirectory that's called media now this is a pathlib object in Python 3 so when we use this operator here this is overloaded it doesn't mean the normal use of that operator which is to divide two numbers with a pathlib object it just constructs a path to a child directory in this case we're creating one called media now what I'm going to do is in the root of this project I'm going to create that media director and it's in this directory that we're going to store uploaded files by users so when users submit the form we want the files to appear in this media directory and we're going to structure that directory in a particular ways to show how we can separate different file types based on a field in the model class so let's now go to the model class that's in the code application and the models.pi fill and I'm going to build a model here and we're going to call this dog and this model is going to allow users to upload pictures of dogs and it's going to inherit from djanglesmodel.model class and we're going to give the dog to a field firstly and name which is simply going to be our car field and we'll get a max length of 64. and the second field on the dog class is going to be the image of the dog and that's going to be equal to a models.image field and this field takes a parameter called upload to and that specifies where in our media root directory that we want the uploaded asset to be placed so for example if I put this here as in the dogs directory what this means is that when we upload a picture of a dog with this form that we're going to build we want that to go into a dog's directory within the media folder so we're going to see how that works in a second that's the two fields on our dog model so let's save this file and we also need to save the settings file with the media directory now you can see below here we're getting some red warnings or errors here we cannot use an image field because pillow is not installed so when you have a Django application that uses these models or image Fields you actually need to install another package which is the pillow Library which is the python Imaging library and that could be installed in your virtual environment with the pep install pillow command once we've installed pillow we can clear the terminal and what I'm going to do now is run the python manage.pi make migrations command and that's going to create the migration file for this dog model that we have here once we've done that we can then run migrate that will create the sqlite database and it will also add this table to the database so this is a model class and the important information for this video is that we have a particular type of field called an image field that's used to store images that are uploaded by users so let's now go to the forms.pi file and at the top we're going to import our new model so from codot Models we'll import the dog model and below that we're going to create a class and this is going to be a model form and we'll just call that dog form and that's going to inherit from Django's model form class now model forms take a meta inner class and you can set the model for the form itself in this class and it's going to be the dog model and we also specify the fields that we want to show for that model within the form and in our case we want to show the name which is just going to be the name of the dog and also the image field as well now that's a very simple model form let's let's go back to views.pi at the top here I'm going to import that model form into the views file and then in the context we're going to create a key called form here and we're going to instantiate that model form and that's going to make it available to us in this index.html template so let's go to index.html and we're going to replace this code here so I'm going to remove that and I'm going to paste in some code that I've prepared here and as you can see this is very simply rendles the form directly without any styling or anything else and below that we have an input of type submit and that's going to allow the user to submit the form to the server so let's go and see how this looks we're going to run the python manage.pi run server command and if we go back to our page you can see that we get this form and because we're using Tailwind the default styles of the browser have been completely removed so this looks really bad it's not very good at all now to improve the styles of this form what I'm going to do is go back to the server here and I'm going to install Django widget tweaks and we're going to render these fields with some classes from Tailwind so as once we've installed widget tweaks with the pep install command we can go back to our settings.pi file and we're going to add the widget tweaks to the installed apps here so that we can use the template filters in that Library so we'll add it to installed apps and we'll go back to index.html and at the top here we need to load the widget tweaks template tags so we're going to say load widget tweaks and let's remove this form thing here and we're going to replace that with some HTML and we're going to use widget tweaks to render some classes so let's create a form element first of all and I'm going to cut this input element and put that into the form so it's actually going to submit this form when the user clicks submit now in the form we're going to add a couple of attributes to the form element in HTML firstly we're going to give it a method of post so it's going to send a post request when the form is submitted now the second attribute we're going to add here is called ink type and that stands for encoding type and as you can see in vs code when the value of method is post ink type is the main type of content that's used to submit the form to the server and what we're going to use here is multi-part form data and that is the value used when an input element has the type attribute set to fail and we're going to have a file field that's going to allow users to upload an image here so we're going to set the encoding type to multi-pot slash form data and this is an essential attribute to add to a form when you're submitting fails to a server so make sure you add that now just under the form element because we're submitting this with a post request we need to add Django's csrf token to this form so we can do that with that syntax there now within the form itself we're going to add the code for two different fields firstly it's going to be the name field for the name of the dog so I'm just going to paste this code in here and as you can see we have a Dev that wraps a couple of statements in the Django templating language firstly we have the form dot name and then we use the Django widget tweaks add label class and I'm adding a bunch of styles from Tailwind if you want to scale these up I'll leave a link below the video to a page that allows you to style up form elements with Tailwind but what we also have of is the widget tweaks render field template tag and this actually renders out the form input field itself in our case it's the form dot name field here for the name of the dog which is simply going to be because it's a car field it's just going to be a type of text and you can see we've attached a bunch of classes to that field and quite a lot of them as well again that's coming from Tailwind I'm going to copy more code below that and this is for the fail input field so here we have another div that's wrapping the code and again we're using the render field template tag and this time we're rendering the form dot image so that's the image field on the form class that is actually the file field that we're going to use to upload so let's now save this file and we're going to run Django's server again and we're going to go back to the page and we're going to see how this page here has changed with our new Styles so let's refresh the page and you can see that it looks much better it's not perfect of course you would still this up better than this but it's fine it's got a name field for the dog's name and this is an image field that you can use to upload a picture of the dog now there's a page here that'll also link below the video this is tailwind and it's coming from Flow by and it allows you to style up these fail input Fields using code that's given to you here so I'll link that below the video if you're following along and you want to steal things better than this now what we need to do now if we go back to our index.html you can see we're sending a post request to the same endpoint that this form is actually displayed so right now what we see on the page this is done by a get request when we submit the form it's going to send a post request to the same URL so what we need to do is go back to viewers.pi and within this view we also need to handle the case where we have a post request and we can do that by checking the request dot method property if that's equal to post then we can handle this in a different way than simply rendering the form and the context so we're going to create a variable called form and we're going to again instantiate the form class but we're going to pass a couple of arguments through that firstly we're going to pass the request.post dictionary and that's key value appears that represent the data submitted by the user but because we have a fail field in this particular form we also need to pass a separate data structure and that's request dot files and that contains any files that have been uploaded as part of the post request so that will create the form and then we can check if the form is valid using the form.isvalid method now if this form is valid we simply want to save it to the database because it's a model form we can just call the save method on that form and that's going to create a dog object in our database if the form is not valid what we want to do is re-render the template with the errors on the page so if the form is not valid we're going to create a context here with a key of form and we're going to attach the form that we have that contains the errors and then we can just copy this render statement and render the same template but this time with a populated form so let's minimize all these directories now notice that we have nothing in the media directory at the moment what we're going to do is go back to the page we're going to try uploading our form here so I'm going to refresh and we're going to fill this form out with some data so let's give this dog a name of Charlie and we're going to upload an image here so here we have a couple of images firstly there's a PNG file and there's also a JPEG I'm going to select this PNG file and we're going to click submit here and see what happens now you can see that it's reloaded the page now what I want to show is whether or not this file has appeared in our media directory so let's minimize all of these now you can see that the media directory doesn't contain any files but we do have this new directory that's came out of nowhere and it's called dogs now this directory contains the file that we uploaded and you can see this amazing dog here so the question is why is this appearing in its own directory instead of appearing in the media directory and it's actually because I've made a mistake here if we go back to settings.pi I've called the setting that we did at the start of the video mediator this should be actually media root this is the root directory where all media files are stored so you need to rename that as media root now what I'm going to do this dogs directory I'm going to move that into the media directory and that is going to then create the file in the right location because remember with then the model file we specified that the files uploaded to this model should be placed into a directory under the media route that's called dogs so now we have the correct structure we have a media directory then we have our dogs directory that contains all of the uploaded assets so let's try this again and hopefully we'll see more images appearing in this directory let's go back to the form and we're going to create a new dog and this one's going to be called Cooper and we're going to create another upload this time we'll upload the jpeg file and we can submit that and let's go back to the server and we can see that we have now within this dog's directory the dog.jpg file so Django is now uploading all of these assets to the correct media directory it's called the media root setting now what I want to do as well is show the database if we open up the sqlite Explorer on vs code we have our dog table we can show that table and see what we have in there now we have two Fields firstly we have the name that's just the varcar field and the second field which is the image field is called image and that stores a relative of path from the media route to the actual file itself so it's going to go in the dogs directory and it's going to look for these files within that directory so this is an important point in Django the database is not storing the file itself it stores a relative path to that file in your media route or another storage system the files themselves by default are stored on your file system as you can see here where the files are stored under the media root directory so now that we have that what I'm going to do now is build a list view where we can actually display these files and display the images on another page in our website so let's go to viewers.pi and just below this view I'm going to create another one that's called list docs and as normal with Django that's going to take the request as an argument and what we're going to do is we're going to create a variable called dogs and that's going to be equal to dog.objects.org so basically we're getting all dogs from the database and we need to import that model at the top so let's go up to the top here and from core dot models we can import the dog model so let's go back down to our new view here and we're going to return a template called list.html so what I'm going to do is create a context variable here and we're going to create a context variable called dogs and we're going to map that to all the dogs in the database and then attach that and render this template called list.html so we need to go to our templates directory and create that new template here it's called list.html and we're going to fill that out with some HTML code in a second but for now let's go back and save the viewers file and we're going to go to urls.pi I'm going to create a new URL pattern here that's going to map to that new view that we've created and it's the second one here so when the user goes to the list URL it's going to load up this view called list dogs and that's then going to render this template so let's now fill in this template first of all we need to extend our base template so we'll grab this code at the top here and paste that in now within this list.html I'm going to grab some modified code from Tailwind there is a page here for the Tailwind CSS project that contains some cards that they have got and these cards there's some HTML available for you to copy and paste so what I'm going to do is paste a different version of that into this template and that's going to be within a block called content so we create our content block that extends the base one and then within That We're looping over each dog and our context and we're going to display a card for that dog and here is one of the important tags in the card is the image tag and the source for that image is equal to the dog dot image.url now that's the actual URL for the dog's image that we've uploaded to the server if we go back to models.pi we have this field on the model called image this is an image field and the objects that represent these image and file fields in Django they have a property called URL and that maps to the actual URL for that object so we can use that here in our list.html to get the proper source for this image for the particular dog in the card so let's save that file and actually before we go on here just at the top of the page before we go into the for Loop I'm going to add an anchor type that goes back to the other page which is the upload form and you can see here we're using the URL template tag to reference a named URL that's called upload fun so we need to give this first one a name called upload form as well and then the index.html template that's the one that contains our actual form we're going to add another anchor tag at the top here and this one's going to link to our list page as you can see we reference the URL called list View and then we can go to the list page and actually view all of the uploaded objects so let's save all of these files and we're going to go back to the page and I'm going to refresh this page you can see we have a new Link at the top here if I click view all dogs you can see we're taken to a list View and we get the two dogs that we have in our database but there is a problem here and that's that the image is not showing now the reason for this is that Django by default does not serve these media files during development it's not recommended in our production environment to serve your media files or any kind of assets like that through the Django server itself so I'm going to go to the documentation here and I have a page on how to manage static fails and on the right hand sidebar there's a section for serving files uploaded by a user during development so let's click that and as it says here during development we can serve user uploaded media files from our media root using the serve View and as it says here it's not suitable for production use so make sure you don't do that in a live project but what we're going to do is just copy this code here these Imports and we're going to paste them as it says here into the root URL configuration which is the projects urls.pi file so we're going to open that urls.pi fill and at the top I'm going to paste those two Imports and let's go back to the documentation and we're going to grab this statement here that we're appending to the URL patterns so let's go back to the urls.pi file and paste that in now this uses the static helper function and we pass through that the settings dot media URL which we're going to create in a second as well as the media root and that's the one that we already have here at the bottom and that specifies where the media files live so we're going to create a new one called media URL here and that will tell Jan angle the URL that is going to serve these static files and we're just going to serve them from slash media and make sure you have the slash at the start and the end of that string if we go back to our list view now and refresh the page we can see that we actually get the two dogs appearing on this page and that's because now after adding those settings the media URL and also the URL conf settings where we are appending to our URL patterns this static function call after doing that we can then serve the media files with Django and that's why we now see these images now we can go back to this form here and I'm going to actually change what's on the model so let's go to the models.pi file and it's this upload to let's just change that to cats to demonstrate what happens here if we go back to our form and we fill in the name of this car I'm just going to give it a random name here and we'll submit this JPEG that is not of a cat but we're just doing this for demonstration purposes when we submit that if we go back to our server's file system the media directory you can see we have a new subdirectory within that and that's the cats subdirectory and that contains that jpeg that we just uploaded so this is how you can have different directories for different file and image fields in your Django models so it allows you not to just bundle every single asset uploaded by a user into the same place you can structure Things based on the different fields that you have and you can even say upload to to a callable to a function that will then create a dynamic folder so this is essential to keep things organized on your server if you are uploading a large number of files of different types now there's a couple of things to show in this video before we finish first of all we have an image field here there are a couple of attributes on an image field that are not declared on a standard Django fail field we're going to see these now in our list view so let's go to list.html and underneath this lorem ipsum on the card I'm going to paste here some paragraph tags and what you can see here is we're referring to the dog door image which is the field on the model and that field has a size property that will tell us the size of the image in bytes and also has a width and a height and these are calculated by the pillow library that we installed earlier in this video it calculates these properties of the image so let's go back and we can go to our list View and hopefully we're going to see these properties so for example this top image of a dog you can see the size of that image in base and you can see that the width and height are those particular numbers and that is repeated for each of these images and the data set that's coming from our database and of course the images are coming from a media root directory so let's now finish this video we're going to add a delete button to each card that represents a dog and we're going to allow users to delete this object from the database and we're going to show how to delete the file from our media root as well so let's go back to the list.html and just within this card underneath those attributes that we just declared I'm going to paste some more code and it's just an anchor tag that links to a URL that we've not defined yet we're going to do that in a second and that allows users to delete the image so let's save that and go back to our card page and of course we get this error because was this URL pattern has not been found so let's go to the views.pi and we're going to define a view just below here that is going to allow us to delete this particular object from the database so let's define the function it's called delete image and it's going to take the request as a parameter and I'm just going to pass on that for now what we're going to do firstly is go back to urls.pi and we're going to write a URL pattern for the delete image view this is going to be a path object and we can specify the URL here we're going to have a delete and then we're going to use a dynamic parameter here and it's going to represent the primary key of the database object that's being deleted so we'll use this syntax here and that means that in the URL we're expecting a dynamic parameter here and it's called PK and let's link this to our new view which is called delete image and we'll give it the name that matches what we have in the delete button that we've just added and it's this one here it's called delete image so let's copy that and paste that into the name parameter in the path now because we've named this Dynamic parameter PK what we're going to do is go to views.pi and that is then accepted as an argument to the view function so we're going to add a primary key as the second argument after the request object and then because that's being passed into the view we can then look up objects in the database by that primary key now what we're going to do is I'm going to scroll to the top of this file and we're already importing the render function from Django's shortcuts module I'm also going to import a couple of other objects or functions from that module firstly get object or 404 and also the redirect function because after we delete these objects we want to redirect to another page in our application so let's now go back down to review and we're going to fetch the dog from the database by using that get object or 404 function the first parameter to that is the model that you want to fetch from the database and the second is the lookup expression that you want to use in our case we want to search for the primary key based on what's being passed into the view function which is this parameter here now that's either going to fetch a valid dog object from the database or it's going to return a 404 not found if one does not exist with that particular number if we get to the next line in this function we're going to call the dog dot delete method and that's going to delete that object or that Row from the database and finally we can return the redirect method so I think after deleting an object from the database it makes sense to return a redirect to the list view so that you can then see the list after that object has been deleted so I think that's all we need to get this delete functionality started it's not going to work perfectly as we're going to see but let's now refresh the list View and now you can see we have this delete image button just below the text not the best use of margins here as you can see it looks horrendous but what we're going to do is actually try deleting this from the database so if we click this button delete image it's going to send a request to the back end and as you can see it's redirected us back to the list page and that particular image that was at the top is no longer found if we go back to the server you can see a get request was sent to the delete 1 and 1 represented the primary key for that particular dog that's then went to this view it's fetched that dog by the primary key and it's deleted it from the database if we load up the SQL light Explorer and go back to the dog table you can see that we now have two dogs in this database one of them has their image in the dogs directory and the media root and the other one has it and the cats directory somewhat confusingly but if we actually go to the media directory here you can see that we have the image for the cats directory but in the dogs directory we actually still have both the images the one that was deleted was this PNG file here we just deleted the object the rule from the database but the image itself is still in the media folder now this might not be a problem but if you want to keep the complete consistency between your database and what's in the media folder you might want to actually remove this file from your file system when the row is deleted from the database that's not done by default in Django so just to demonstrate what I mean I'm going to delete this one from the front end that one is the one that is in the cats directory so let's go back to our page and it's the one below here with this name if I click delete here it's going to remove that from the database so let's go back to vs code and if we reselect everything from this table you can see we now only have one row in the table but in the cats directory we still have the jpeg file it's not removing that from the media root so let's close SQL Lite now and we're going to go to some documentation for our library called Django cleanup we're not going to install this in this video but in production you may want to use this and as it says on the right hand side this Library automatically deletes old files for your file fields and image fields in a Django project and it also deletes files when you delete the model instance and that's what we just did with the dog object we called Dog delete in the view that's deleting the instance and then this particular Library would then clean up the files in your media router but also delete those files as well as the role in the database now that's a solution that you might want to use in production we're going to use something different here so I've loaded a page in Django's documentation and that's this section here it's about overriding predefined methods on models now you might commonly use the save method you might override that in your Django model to perform some sort of logic when you save a Django model instant it turns out djangles models also have a delete method and you can use that to perform any logic you want when you actually delete a row or an instance from the database and here there's a link to the delete method or a section and documentation for that under the hood the model will issue a delete statement in SQL to the database to actually remove the rule from that database so what we are going to do is go to our dog model class and that's going to be within the models.pi file and we're going to override the delete method now this method is defined on a python class so it takes self as the first parameter and what we're going to do is when we're deleting this instance we're going to access the image which is an image field and then image fields and fail fields in Django they also have a method called delete which will actually remove that file from underlying storage in our case the file system storage after the deletion of the file we can just continue as normal and we're going to do that using the super.delete method and the superclasses delete method is what performs all of that SQL logic to delete the row from the database now this will work when you delete a model instance but it will not work if you delete a query set of models and it's possible in Django to get a query set multiple models and call a delete method which will remove all of them from the database so that's something to be conscious of if you're removing a lot of objects at once with a query set this delete function is actually not going to get called the query set delete function will get called and if you want to remove your file fuels you should use that Django cleanup package or you could also Define a Django signal which can respond to delete events that come through for particular models in your application but that's beyond the scope of this video if you're interested in any of that let me know in the comments what we're going to do now is test deleting one of these last objects that we have in the list view it's this one here for the dog Cooper let's delete that image now we have no more images to show on this list page but if we now go back to the server and we go to the media directory you can see within the docs directory it's actually removed that jpeg image that represented that dog so not only are we removing the role from the database we're also removing the underlying file from the file system so that's maybe a better solution if you want to keep your file system clean when users are deleting these objects so that wraps up this video in the next video I'm going to dive further into handling media files and uploads in Django and we're going to see how to upload images and files to Amazon's S3 service and we're going to use a tool called Django storages to do that we're also going to see how to use signed URLs with Django storages to upload files to S3 and make them available to users only for a determined period of time so these are URLs that expire after a certain number of seconds I'm going to see how to implement that and then we're going to go on and see how we can use cloudfront with Django cloudfront is a CDN that's part of the Amazon ecosystem and you can put that in front of your S3 buckets to rapidly serve your content to users throughout the world throughout Amazon calls Edge locations we're going to dive into all of that in the next video as well as the benefits of Hosting your files on a cloud storage system like S3 but for now thank you very much for watching this video I hope you've enjoyed the video if you've learned anything please like And subscribe to the channel and we'll see you in the next video
Info
Channel: BugBytes
Views: 19,571
Rating: undefined out of 5
Keywords:
Id: lKyH_ZGtvwM
Channel Id: undefined
Length: 30min 15sec (1815 seconds)
Published: Fri Mar 10 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.