django-crispy-forms & ModelChoiceFields / Select2 Integration for Searchable Form Fields

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
often when you're working with forums in Django you have to select related objects in a form field and in this video we're going to learn how to do that with Django's model Choice field we're going to learn how to load options for foreign Keys into a form field and then we're going to use select to in order to make the drop down searchable and that will help us find the item that we need in the most efficient manner and after we've done that we're going to look at another Django form field we're going to look at the model multiple choice field and that lets you select multiple related objects in the form and attach them to that object in the database and when we're building these forms we're also going to use djangle crispy forms in order to make the forms look good using bootstrap so let's get started I have the GitHub repository open here for the starter code I'll leave a link to this below the video you can clone this in order to get started and I already have this open in vs code so let's bring that up now what we have here is two Django models we have a car model and a user model and you can see the user model we're extending the Django abstract user that contains all the default user model Fields such as username and email address we're extending that and we're adding a single additional field here and that's the car foreign key and that's a foreign key to the above car model and that model is a very simple model it contains two car Fields the first one for the manufacturer of the car for example Ferrari and the second is the country to which that car belongs now the reason that we have a car model here if we go to the data directory that's in the starter code we have this cars.csv file and if I click on that you can see the data that we're going to use in this application we're going to populate the database with these cars and then we're going to use a model Choice field and a Django form in order to allow users who are registering to select which card they have in a drop down so that's the data set and what we also have in this starter code is a management command called load cars and this is a very simple Django management command it contains this handle method and we have a link to that CSV file containing the card data and then below that we're reading the file into memory and and for each row in that file we're using the card.objects.get or create function in order to get that object from the database and if it doesn't exist create it in the database so that's our starter code what we're going to do now is go to forms.pi and we're going to create a form that allows a user to register into this application and as well as some of the default fields that are on a registration form in Django we're going to also add a model Choice field in order to let the user select a car so let's go back to the browser and this is the manufacturers.csv file that I've already got in the starter code I'll leave a link to this repository in the description as well what we're going to look at now is this page here on creating a user using the Django user creation form and this is a form that's built into djangles auth package it's called the user creation form so what we're going to do is go back to forms.pi and we're going to bring that form in as an import at the top here so from django.contrib.auth.forms We're importing the user creation form and we're also going to bring in the user and car models from the models.pi file so let's create a new class here it's going to be called user create form and it's going to extend that user creation form from Django and we're going to define a meta class underneath that there and we're going to link this to the user model that we've created in the models.pi file and that's this model here that extends the abstract user and adds this car field to that model so we're tying this form to the user model and we're going to Define now the fields that we want to show in the form so we're going to show the username as well as two Fields called password 1 and password 2 and finally we're also going to show the car field and that's going to show that related model Choice field in the form if we go back quickly to the documentation for the user creation form you can see that it inherits from the base user creation form and if we scroll up to that particular form class you can see some more details on what this is It's a model form for creating a new user and this is the recommended Base Class if you need to customize the user creation form and you can see that this model form has three field the username the password 1 and password to view and by default the form will verify that password 1 and password 2 match and then it will also validate the password with the validate password function and it's going to set the password with the set password function and that's important because it's going to take the raw password and it's going to Hash that so when you're extending these forms you don't need to worry about the password hashing logic so if we go back to vs code we're creating a form called user create form that is extending that user creation form and we're referencing the free fields in that form and we're adding another field and that's the car foreign key what we now need to do is add this form to a review context so let's go to viewers.pi and at the top here I'm going to bring in from the core.forms module that new form that we've just created and then to the context dictionary we're going to add a key called form and we're just going to instantiate that new form object now you can see that the return method for this view is rendering this particular template called register.html so if we go to the templates directory we're going to able to register.html and you can see at the moment we just have an H1 tag what we need to do below that is create a form tag in HTML and we're going to give this a method of post so that when we submit this it's going to send a post request to the Django server and of course when we're sending a post request we need to also include the csrf token so we're going to add that template tag there and then below that we're going to take the form that we have in our context and we're going to render that using the as Dev property and that's going to create each field in the form on a new line and finally I'm going to add a button here and that's a submit button that's going to submit the data from the form to the server so the next step here would be to run the server but before we do that I'm going to run the Django manage.pi migrate command and that's going to create the SQL Lite database in this application and what we can then do is we can run Python manage.pi and we're going to run that custom management command that we have in the management folder it's called load cars and that's going to load all of those cars from the CSV file into the database and I've reference load CSV that should be loads cars and that's going to then load all of those cars into the database and once that load cars command is finished we can go to the Django shell and I'm going to run a query here that's card.objects.org I'm going to see that that returns a query set of car objects and if we run card.objects.org and chain the dot count function to that it Returns the number of cards in the database and we can see that there's 43 cars and that hopefully matches what we have in the CSV file so let's open that file and if we scroll down you can see we have 43 rows of data so that matches all of these cars are now loaded into the database let's now exit the shell and we're going to start the Django development server and we're now going to go to the browser and you can see the form that we have on the browser here it's not the best looking form but the important field to look at is this car field at the bottom and you can see that that has loaded in all of these objects for the cars that have been loaded into the database but you can see that the string representation of these is not ideal just says car object along with the primary key of that car we're going to change that now by going back to models.pi I'm going to add a Dunder string method to the car model that's going to take self as an argument and we're going to return the manufacturer of the car if we now go back to our application refresh this page at the bottom you can see we now have the car manufacturers loaded into this field so this is a model Choice field when you use a Django model form that's tied to a foreign key in this case the phone and key on the user model is the car model the foreign key objects are loaded into the model Choice field and by default they're shown in a select box like this drop down here now in this video we're going to customize this as we progress through the video we're going to add the select toolbox to make this searchable we're also going to override the default query set so that we're not getting all of the cars back but a subset of the cars and finally we're going to learn how to select multiple cars when we are registering here so we're going to change this model Choice field into a model multiple choice field in Django so that's coming up but for now what we want to do is actually just handle the submission of this form this is kind of like a registration form where the user fills in their username and a password and they also add their car manufacturer to this registration form and then they submit that to the server now what we need to do is go back to views.pi and within this register function we need to handle the post request so we're going to check if the request method is equal to a post request and in that case we're going to do things differently we're going to create a form object and we're going to instantiate the user create form and pass the post data into that form so we pass request dot post as an argument into the user create form once we've done that we can check if the data that's been passed in is valid we use the form dot is valid function for that and if it's valid because the form is a model form we can call form dot save and then what we typically do when we submit a form is we redirect the user somewhere else in the application so I'm going to import redirect at the top and that's from Django dot shortcuts and we can pass a named URL and here and what I'm going to do is go to urls.pi and we have a single path in this application for the register page so I'm just going to copy that name and paste it in here so when we submit the form we're simply going to be redirected back to the register page so a very simple form submission process here we create the form and pass the post data in we verify that it's valid and then we save that data to the database let's now see if this actually works if we go back to the page I'm just going to refresh this page and let's create a user here called user1 and I'm going to add a password here and finally we select a car I'm going to select McLaren and we're going to submit this form to the server now you can see the page has reloaded what I'm now going to do is go back to a vs code I'm going to stop the server and we're going to run the create super user command and I'm going to create a user called admin who we can log into this application in the admin UI and view the objects that have been created so we've created that user all we need to do now is go to admin.pi and register our models with the Django admin interface so I'm just going to paste some code in here from code.models We're importing user and car and then we're using the admin.site.register function to register both of those models with the admin let's now restart Django's development server and we're going to go back to the browser and this time we're going to go to the slash admin page and we're going to log in as this new admin user that we've just created and we're going to be taken to this page now what I need to do is actually save admin.pi and refresh this page and you can see now that the models have appeared now we created a user with the username of user1 you can see that user is here and if we click through to the user and you can see some of that user's details here if we scroll to the bottom you can see that the car that's been selected here is the McLaren that we selected in the form so it's correctly attach that foreign key just by selecting that particular element in the drop down and if we follow through to that McLaren object it's our car and its manufacturer name is McLaren and the country is UK so you can see that that is correctly attaching that foreign key and it's doing so transparently by creating that model form which under the hood uses a model Choice field in order to attach the foreign key to that object and just to prove What's Happening Here we can go back to Django's shell and I'm going to get the user that we just created from the database by calling user.objects.first that gives us back this user model here and what we can do is look at the car and we see that McLaren on that and because it's a foreign key we can then follow through to the fields on that object for example the manufacturer if we look at that you can see we get back the string McLaren so let's exit the shell and what we're going to do is start the server again and go back to our form and we're going to change up the form that we've been working with in this video instead of what we see here we're going to use Django crispy forms and that's going to allow us to stale this form a lot better so let's go to the documentation for Django crispy forms and we're going to copy the PIP install command and we're going to bring that into the terminal below in order to install that application once we've done that we can go to settings.pi and if you scroll down to installed apps we're going to add crispy forms to installed apps here and once we've added that we need to add a crispy forms template pack here if we go to thebase.html template and this is the base template in this application this comes from the starter code and you can see we have a link tag that loads up the bootstrap 5 CSS so we need to use our bootstrap 5 template pack for crispy forms and there is a python package that will do this for you it's called crispy bootstrap 5 so we can scroll down here and again I'll leave links to all of these below the video we're going to copy the PIP install command and we're going to paste that into the terminal once that installs we can go back to the documentation and we're going to add crispy bootstrap 5 to installed apps so let's go back to settings.pi and we're going to paste that in here once we've got that we can finally come back to the documentation and we're going to copy these two settings that's the crispy allowed template packs and the crispy template pack we're setting both of these to a bootstrap 5 so let's go back to settings.pi and I'm just going to paste these below the installed apps and save the settings.pi file once we've got that we can go back to register.html this is the template that contains our form and what we're going to do at the top is load the crispy forms tags so that we can actually use these tags in this template and then we're rendering the form below we're going to remove the as div and I'm going to use the crispy template filter here and then we can rerun Django's development server and go back to the browser and we're going to see if this form changes and now that we're using that crispy template filter so let's refresh the page and you can see now that this form looks a lot better and if we scroll down to the car you can see we still get that drop down that select box and all of the cars are present in this list and we can select whatever one we want to now you might notice when we have this open that you have to search for the car that you want to find what we can do is add select 2 to this in order to make the drop down or the select box searchable now to use select 2 we also need jQuery in the application so what I'm going to do is go to the CDN link which I'll leave a link to below the video and we're going to grab this magnified version of jQuery 3.7 and we're going to copy that and go back to base.html and just below the bootstrap CSS I'm going to paste that in there so that's going to bring jQuery into the application and what we also need to do is get select two as well so let's go back to the browser and we're going to copy these two tags and we're going to bring them into the base.html just below the jQuery input we can do that as well so now in our base.html we have bootstrap we have jQuery and we have select2 what we now need to do is add a script here that is going to look for the ID of our select box containing the foreign Keys that's the model Choice field and we need to call the select to function on that particular element in the Dom so how do we do that what I'm going to do to start with is go back to base.html and just underneath this div tag I'm going to define a new block here and it's going to be called Script and don't forget to end that block just below here and what we can then do once we have this block is go to register.html and we're going to over read that scripts Block in here in order to add a script that's going to use select to so what we're going to do within here is Define a script tag and we're going to Target the ID of the element in the Dom that contains our car foreign key and it's going to be ID underscore car and what we're going to do is call the select to a function on that particular element if we go back to the form and we right click the car field and we inspect the source you can see that select element has the ID of ID underscore car and that is what we are referencing here with this jQuery selector and the reason it's called ID underscore car if you don't know this if we go back to forms.pi the field in the form is called car and when Django renders these forms in a template it adds the ID prefix to the field name so let's go back to register.html and this simple line of code that we've defined should allow us now to search in this Dropbox so let's save the file and go back to the browser and we're going to refresh the page and close the developer tools now at the bottom you can see that this looks a bit different now when we click that we have the search bar at the top so if I wanted to find McLaren I can type into that search bar and it Narrows down the options based on what I've typed so now we have a working select toolbox that allows us to search through these options let's now move on and see how we can limit the query set of objects that appear in this select box now by default it shows all of the cars in the database so if we go back to forms.pi when we create this model form and we create the car field in that this is going to create a model Choice field under the hood that links to a query set containing all of the cars by default what we're going to do now is override that and we can do that by setting explicitly the car field here and setting it to a forms dot model Choice field and to that we can supply a base query set so I'm going to do that on a new line and we can do it with the query set keyword argument now let's say we only wanted to have cars that were made in Germany or Italy in this query set we can use the card.objects.filter function in Django and what we're going to do is we're going to pass the country view and we're going to see if it's in one of the values that we Supply in this python list so we only want cars that are made in Germany or in Italy to be in this query set that is displayed in the select box if we now save the file and go back to our form and refresh this page if we look at the drop down below you can see we have much less options now we only have cars whose manufacturer is based in Germany or Italy so what we need to do if we want to override the default query set as we can explicitly set the model Choice field on our Django form and then we can supply That Base query set as an argument to that field on creation and in this case it's card.objects.filter and we're filtering down to only cars from Germany or Italy so this is a model Choice field in Django that links a particular model to a foreign key but what if you want to potentially link multiple models to another model for example in this case we want the user to be able to select multiple cars in this form and when we save the form it's going to save all of those car relations to the database in order to do this we have another form field that we can use rather than the model Choice field we can use the model multiple choice field instead but let's see how to do that by default without explicitly defining it first so what I'm going to do is rename the field here to cars in this form and then I'm going to go back to models.pi and we're going to change up this foreign key here instead of a foreign key we want to potentially allow the user to select multiple cars so I'm going to get rid of these arguments I'm going to change the foreign key to a many to many field in Django this allows one user to be linked to many cars and it allows a particular car to be linked to many users and we need to rename this field cars that would make more sense for a many-to-many field once we save that we can stop the server and what I'm going to do is run the make migrations command in Django you can see this migration removes the car field and it adds another field called cars to the user model once we've done that we can then run the migrate command and that will apply those changes to the database let's now run the server and go back to a form page and refresh this page and we can see at the bottom we have this cars field I'm going to make this a little bit smaller and you can see we can now select multiple cars from this field it doesn't have the best UI representation though and this is actually the default widget for a model multiple choice field in Django but it turns out we can use select 2 and select multiple elements with the select to Dropbox what we can do is we need to change the ID that's being referenced here if we inspect the Dom for this field we can see that the ID is now ID underscore cards and that makes sense because in the form we renamed the field from car to cars so we need to change the ID that's referenced in the register.html file instead of ID card we are going to Target the new ID here if we save that and go back to the page I'm going to close the dev tools and refresh at the bottom you can see we now get this multiple select field so for example I can select Audi here and then I can go back in and select Alfa Romeo we can select as many options as as we want from this field it's a model multiple choice field and if we inspect the Dom again here what it does is add this multiple attribute to the select element and that therefore allows us to select multiple elements and select two gives us a nice interface to do that so let's now try saving this user to the database we'll give them a username of user2 and once we fill the password out we can submit this form and we're going to then be redirected back to the page if we go to the Django admin though when we refresh this user list page we can get this new user called user2 and when we go in there and scroll down to the cars you can see that multiple of these cars have been selected and that is the selections that we made on the front end each of them has been passed to Django and each relationship has been created in the database now just to show how this is done in the database I'm going to bring up the database browser for SQL Lite and you can see in the user table here that we have the user with the username of user2 and they have a primary key ID or of five now if we go back to the database structure you can see there's a table here called core user cars and this is the many-to-many junction table that links the users with the cars and it does so in a way that allows as many of these relations to be created as possible so if we browse that table you can see the structure of that table each row has its own primary key but importantly it has two foreign Keys one to the user table and one to the car table now for that user that we had on the admin we created four cars tied to that user one for Alpha Romeo one for Audi one for Lamborghini and one for McLaren if we go back to the database browser you can see there are four rows in this table and they're all tied to that user with the ID of five and there's four cars that are tied to that user so what happens when you create a many-to-many field in Django is that a table is created in the middle of the two models involved and that allows you to link a particular instance of one of the models to as many of the other model as you want so with that said we're able to create users with as many car as we want in this database as you can see here now there is one caveat I want to mention here if we go back to Django's documentation for the user creation form you can see a section here on what was changed in Django 4.2 in older versions the user creation form did not save many to many form fields for a custom user model so if you're using a version of Django that's older than version 4.2 you will need to handle saving the many-to-many fields yourself after you save the initial model so if we go back to views.pi and we go down to the code that is handling this post request on line 9 here you can see we are calling the form.save method and what form.save is going to do is it's going to create the user that's tied to this form and that's because this is a model form so it's going to create that user in the database but the cars field on the user model is not actually translated to a column in the underlying database because it's a many-to-many relation it creates that Junction table in the middle of the user and the car models and in older versions of angle what you need to do is get the user that's returned from calling form dot save that gives us back that user who is now in the database with a primary key and then you can create the associated records in this table using that user's primary key so what we would need to do then is call the form dot save many to many function in Django and that will then handle saving the many-to-many relations to the database so if you're using a version of Django less than 4.2 you will need to call the forms save many to many function in order to actually create these objects in the database but in Django 4.2 this logic here is no longer necessary because the form class is smart enough to create the user model first get the primary key and then create the associated entries in that Junction table so we're nearly done with this video I want to highlight one last example in forms.pi I want to show that we can also customize the model multiple choice field so what I'm going to do is change this to a model multiple choice field and let's say again we want to customize this query set let's remove the dot filter function and this time we're going to use the dot exclude function and we're going to exclude any cars that were made in the UK so we're going to pass country equal to the UK as a parameter here and I need to also rename this field here to cars if we save that and go back to the form you can see at the bottom we now no longer have UK based cars for example if we search for McLaren that is no longer in the list so that's all for this video we've learned about Django's model Choice field and also the model multiple choice field this allows you to create a form field that's based on a foreign key or a many-to-many relation and when you save a form with these fields Django is automatically going to handle creating that foreign key entry in the database or if it's a many-to-many field it's automatically going to create the many-to-many instances in the junction table and as well as seeing how to use these films we've also seen that we can use select 2 on the films to make them searchable and we can do this both with the normal Choice field and also when we're selecting multiple objects from that field so thanks thank you for watching if you've enjoyed this video please give it a thumbs up and subscribe to the channel and we'll see you in the next video
Info
Channel: BugBytes
Views: 9,459
Rating: undefined out of 5
Keywords:
Id: Zzd4sL7drKQ
Channel Id: undefined
Length: 25min 10sec (1510 seconds)
Published: Thu Aug 03 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.