Django ORM - Model Field Validators / Writing Custom Validators / ModelForms

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this video we're going to take a quick detour and learn about model field validators in Django we're going to add a validator to the rating field to constrain it between 1 and 5 stars and we're going to add validators to both the latitude and the longitude field of the restaurant model in order to constrain their possible values as well finally in this video we're going to learn how to create a custom validator as a function in Python and we're going to see how to attach that validator to a Django field so let's get started I have the documentation on validators open here and you can see that a validator is a callable in other words a function in python or a class with a Dunder call method and the validator should raise a validation error if the value coming in does not meet some criteria so in the Django documentation we have an example validator function here and we can add that to a field using this validators keyword argument in this case that's passed to an integer field on a Django model so Django model Fields can take a list of validators and it's going to run them one at a time in order to validate the value that's come coming in now Django has a number of built-in validators you can see that on the right hand side here at this part of the sidebar we have things such as a regex validator and an email validator and if we scroll to the bottom we also have a fail extension validator which has been used in a previous video that I'll link on the screen just now but what we're going to do in this video is we're going to use these validators here the Min and max value validator and we're going to apply that in one of the fields that we have in our Django models that we've defined in the previous videos so let's go to vs code and I have the models.pi file open I'm going to scroll down to this rating model and the rating model has a field called rating and that's storing the number out of five stars that's been given to the restaurant now at the moment this is just a positive small integer field and that means it can take values that are between zero and numbers much greater than just five what we want to do is constrain the values that can be input from a Django form to between the number one and five so what we're going to do is scroll to the top of this file and at the top I'm going to bring a new important from django.core.validators and what we're going to import from that module is the Min value validator and also the max value validator and if we go back down to a rating field now we can add to this our list of validators using that validators keyword argument and we're going to set that equal to a list and we can pass the Min value validator in here and instantiate that and pass the limit value in in our case it's going to be one for the minimum value and remember the validators list that can have more than one validator they're all going to be applied to the value that's coming in and the second validator is going to be the max value validator and we're going to pass the number 5 to that so we have a field called rating which is a positive small integer field and now we are passing a list of validators to that that are constraining the value between one and five and these validators are used for example when we Define model forms in Django that are linked to the rating model we're going to see an example of that in two or three minutes in this video but for now what we're going to show is that this doesn't not work programmatically we can actually enter ratings that are greater than five for example or less than one and that's because these validators are not database level constraints they are just applied through Django forms now don't worry if this is a little bit confusing at the moment we're going to show some examples in this video and get to the bottom of these validators so what I'm going to do is go to the scripts directory and I'm going to go to the orm script.pi that we created in the last video and I'm going to remove the call to get or create now what we have here is a user and a restaurant that we're pulling out of the database by using the objects.first function what I'm going to do now is try and create a rating so let's use the rating.objects.create function and we're going to pass the user and the restaurant that we pulled out of the database to that rating and finally we need to also pass the numerical rating now what I'm going to do is pass a value of 9 here and that should not be allowed of course because we're constraining the ratings between one and five but what we're going to see is that that actually does enter this data into the database so if we run the python manage.pi run script command and the name of the script is orm script when we run that it's actually going to add this rating to the database and if I open up sqlite browser here and we go to the rating table and browse that table you can see the last row in that table has a rating of nine so even though we've added these validators to the Django model field it is still allowing the programmatic creation of a rating with a rating value of 9. now I want to go back to the Django documentation for a second I'm going to scroll up to this section here how validators are run you can see the note here that validators will not be run automatically when you save a model but if you're using a model form it's going to run your validators on any fields that are included on the form to see how these are run with models we can click the validating objects link here and it turns out if we call the models full clean method before we save the model then that's going to run validation and it's going to run those validators to determine whether we have a valid instance of the the model so let's demonstrate quickly the full clean method and then we're going to move on to the Practical example of creating a Django model form and we can see the effect of these validators in the model form now within this script I'm going to remove the call to create and I'm just going to create a variable called rating and instantiate the model passing those values now what we're going to do below that is called the rating dot save method but before we do that what I'm going to do is call the full clean function and that's going to run the validators and what we're going to see in a second is that the fill clean function is going to throw the validation error because of the validators we've added to the field so let's make the terminal a little bit bigger here and run the script and you can see we are getting a validation error and the field where this error is occurring is the racing field and we need to ensure that the value is less than or equal to 5. now the validator that's causing this error if we go to models.pi it's the max value validator and the reason this is happening is because in our script here we are passing a rating of 9 which is greater than 5. so when you call the rating.c save function by default it's not going to run the validators that are applied to the fields but if you do run the full clean function then it will apply those validators now let's see a more practical example by going to forms.pi and we're going to create a model form for the rating so at the top we're going to import the rating model and just below that we're going to create a class called rating form that will inherit from the forms.modelform class within the model form we're going to create a meta class here and we can link the rating form to the rating model using the model field and we can specify the fields we want to show in the form so by showing the restaurant and the user because the required Fields the other foreign keys on the rating and we're also showing the numerical value for the rating as well so that's a rating form let's copy the name of that and we're going to go to viewers.pi and at the top from the forms module let's import that rating form into the views.pi file and I'm very quickly going to write a function here that is going to handle the submission of the rating form with a post request as well as rendering that form on a get request so this is our view when we have a post request we're going to instantiate the form and pass the post data to the form we can then check if the form is valid using the form.isvalid function and if it's valid we can save that model form and that's going to create the rating record into the database otherwise if the form is not valid we'll hit this else Clause where we re-render the template with the form containing the errors and if we don't have a post request we're just going to add the form to the context and then we're going to render the index.html with that context if we now go to index.html we're going to add the form into this particular template and I'm just going to paste some code to do that where we Define a form element and of course we use the Django csrf token for security because we are sending a post request here below that we use the form that we've added to the context and we render that with paragraph tags and finally we add a button that allows us to submit the form now if we go to urls.pi you can see we have one path in this application that maps to the index viewer that we be defined and that's this one here that handles the post request and also the get request for the form once we've added this code we can run the Django development server and when the server is running we can go to localhost 8000 and we can see our beautiful looking form on this page so we can select a restaurant from the restaurants that exist in the database and we're going to use the admin user as the user here now what we're going to do now is select a rating let's say three out of 5 Stars when we submit that that data then goes to the database and that's because when we call the model form dot save function it's actually going to save the data to the database for the model to which this form is attached in our case that's the rating model so when we go to the database with the sqlite browser here if we refresh this table you can see the new record has been added let me order that by ID you can see that at the bottom here it's this row with the rating of three and that's the one that we just added now remember model forms do run the validators that are on our model Fields so this menu validator and the max value validator these will be checked when you run a model forms as valid function so unlike the programmatic example that we had in this script where we set the rating to nine and we didn't call the full clean function we cannot actually save a model form that has a value that does not conform to what's in these validators so let's see an example of that now if we fill in this data and this time we select the rating as nine you can see we get back the form with the error attached to that field we need to ensure that the rating is less than or equal to five so if we put any value that's above 5 here it's not going to accept the data and that's because of the validators that are attached to the model field the model form knows about those validators and it uses the logic within them and applies that when we submit the form and similarly because the minimum value is set to one if we try and submit a rating of zero here you can see we get a different message we need to ensure that the value is greater than or equal to one so model forms are tightly bound to the Django model Fields validators the validators you define on the model field will apply within the model form Fields as well and we can actually reuse these validators in a normal Django form class so if we go to forms.pi here I'm going to remove this rating input and I'm going to replace it with the Min and max value validator and I'm going to change the model form to just a normal Django form class and we can remove the meta class as well and this time we're going to define a single field and that's going to be a forms.integer field and I'm going to pass the same validators that we used in the model here and that's these values here let's pass them into the form as well and that's a list of validators so it's not only Django models that take the validators keyword argument you can also pass that to form fields and Django as well if we go back to the views.pi fill we can no longer call the save function because it's no longer a model form so calling save does not make sense because it's not tied to a particular model so I'm going to remove that line of code and this time let's just print out the form.cleaned data whenever a form is submit and that form is valid we can see that printed out to the terminal so all that we're going to demonstrate here is that we can reuse these validators in form Fields as well let's go back to our page and this time when we refresh the page we just have a rating field here so if we submit a rating of three that's going to be valid and if we go to the server we can see the data coming through in that post request but if we go back and try and submit a rating of 9 here you can see again we're getting these errors but this time these errors are not coming from a model form that's tied to a field on a Model but we have actually explicitly defined them on the form class itself so validators are reusable between forms and models in Django let's add some other validators to our application here this is on the JavaScript API for Google Maps and you can see that latitude for example has a range between negative 90 and 90 degrees and that's inclusive and longitude ranges between -180 and 180. so we're going to add validators to the Django restaurant model in order to validate these values that are coming from forms so let's go back to the models.pi file if we scroll up to the restaurant model you can see we have two float fields for the latitude and the longitude now at the moment these two Fields if we use the model form for example they would allow the entry of any value that is a valid floating Point number but we're very quickly just going to add to a validators here so for the latitude I'm going to add the validators keyword argument to this field and this time the Min value validator we're setting that to minus 90 and the max value to 90. and just below that in the longitude field here we can set the values to minus 180 and 180. now again we can programmatically create a restaurant and set the latitude and longitude to values that fall out with these boundaries the validation on the model Fields is only going to run if we call the fill clean method but if you actually want to apply this kind of constraint at the database level Django does allow you to do that using database constraints which we're going to see in a video later on in this series and ideally you want to do both actually you want to define the validators so that your forms understand the logic that should be acceptable but you also might want to provide the backup to prevent any errant values going into the database as well by defending database constraints and if you have complex Logic for a validator for example you need to validate a particular pattern you could use something like the regex validator for that now let's finish this video by writing a custom validator in Python and then applying a custom validator to a model field in Django now so far we've relied on these validators that are coming directly from Django and these are defined in Django's validators module we're now going to define a dummy validator that's going to just demonstrate how we can write a function that might validate an object so for the restaurant model here let's say we had some bizarre requirement here with the name of the restaurant must begin with the letter A we can write a custom validator for this logic so what I'm going to do is write a python function above the class and let's give that a name of validate restaurant name begins with a now validator functions they take value in as an argument and then you can perform the logic to actually validate that value within the body of the function so what we're going to say here is if the value does not start with a so if not value dot starts with and then we'll pass the letter A into that if it does not start with a we're going to raise a validation error and we do need to import that from django.core.exceptions we're going to raise that validation error and we can pass a message to that so let's pass a message here that the restaurant name must begin with a so we're only going to raise this validation error if the restaurant name does not begin with a that's all we need to do in the body of this validator so let's now copy the name of the validator and we're going to scroll down to the name field and that's the field we want to actually apply the validator to so to apply that let's pass our validators keyword argument here and again that's a python list and all we need to do and there is past the name of the function importantly we do not instantiate the function we just pass a reference to the function and then the function will be called whenever any sort of value is coming in and is trying to be validated so that's our validator we're going to finish this video up by going to forms.pi and I'm going to replace the rating form with another model form here that's tied to the restaurant and let's import that at the top from core dot models we can import the restaurant model and the field that we are actually going to display on this model form is the name field and we want to validate that and make sure that the name does begin with a and when we enter a value that does not begin with e we want to see that validation error coming onto the page so this form is called restaurant form let's go back to views.pi at the top I'm going to import that form and we can replace all references to the rating fold that's all we need to do to show this on the page so let's go to the web page and if we try and submit a form with a value that does begin with e that's going to go through successfully if we go back to the server we can see that's being printed out onto the terminal and that's because form dot is valid is returning true and we're printing that to the terminal let's now see an example where the form is going to reject a value so if we input a value that does not start with a when we submit that we get back the message that the restaurant name must begin with a and that's because other custom validator in the models.pi file this validator here will check that the value starts with a and if it does not then it's going to raise this validation error and what happens when we call the form dot is valid function it's going to check the values that are passed into the form and if we have any validation errors that's going to return false and that's why this else block is executed and that's why the form that's added to the context is this populated form containing the error that we see on the page here so the key takeaways in this video are that we have the ability to add validators to fields in Django and also to form Fields as well as model Fields but validators do not protect the Integrity of your data entirely they are not used when you call the model.save function but instead they are used when you call the model.fill clean function or when you try to save a model form and that's because the fill clean function is called when you try and save a model form if you want want to go one step further and make sure that your database values cannot be outside of these boundaries what you can do is you can attach constraints to the database for example a check constraint or a unique constraint and that will then prevent certain values from being entered into the database even if they pass a form on the front end now one last thing to show in this video where we have a model form here for the restaurant if we go back to the forms.pi and add another field to this I'm going to add the restaurant underscore type field now remember in the first video If we go to models.pi we defined this inner class within the restaurant model and that was an instance of the Django text choices class and that contains some choices for which type of Cuisine is offered by the restaurant we then attach these choices to the restaurant type field using the choices keyword argument now that will have the effect when we Define a model form that's tied to the restaurant model and we use the restaurant type as a field in that form if we go back to the page if we refresh this page we now get the rest front tape field here and we get a select box or a drop down that contains the values that are coming from that text choices in our class so when you define choices in Django using our text choices or integer choices class and then you attach those choices to a model field when you define a module form that's tied to that field that will automatically pull through those choices and display them in the form so that's just an additional note on what we can do with these choices here and why we Define these choices classes and use them within our model Fields so I hope that makes sense and thank you for watching this video in the next video we're going to learn how to update and delete records from the database after that we're going to create a custom data set that's tied to these models and we're going to learn more about how to query the database then we're going to learn about the N plus 1 problem and prefetching data before moving on to defining many to many fields in Django and how you can tie one model to many items of another model and vice versa after that we're going to handle aggregation and annotation in Django and also how to do conditional queries and sub queries and there's many more things prepared for after that as well but if you do have any requests please let me know in the comments if you've enjoyed this video please like And subscribe to the channel and we'll see you in the next video
Info
Channel: BugBytes
Views: 7,976
Rating: undefined out of 5
Keywords:
Id: 1x0Zdukpjrs
Channel Id: undefined
Length: 19min 13sec (1153 seconds)
Published: Fri Jun 09 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.