Regular expressions in URLs
Django lets you design URLs however you want, and you do this by using the path function and path converters.
For example, creating a custom URL with dynamic values for more complex matching requirements, you can define your own path converters using something called regular expressions.
Suppose you have been tasked to create a menu item page for the Little Lemon website. The page displays content for each item on the menu. Instead of making a specific page for each menu item, you can define the dynamic URL structure that will pass the menu item ID to the view function.
The content of the page will depend on the menu item value past to the view function from the URL. Based on the ID value pasta in the URL, the logic in the view function will determine what type of data to display, like a menu item name.
The advantage for developers is that they only need to create one page. Instead of creating individual static pages for each menu item, developers only need to create one page whose content updates dynamically based on the values past in the URL.
However, to ensure that the URLs structured in the way that the view function requires, you need a way to define and verify the values and format of the URL. To verify that the URL values pasta to the view function are correct, you can use regular expressions.
RegEx
RegEx
Regular expressions or RegEx, are a set of characters that specify a pattern and are used to search for or find patterns in a string. They are a powerful tool that developers use to perform extraction and validation, advanced searching, group searches, and find and replace operations.
In django, developers use regular expressions to define, extract and validate dynamic URL paths before they are sent to the associated view function.
However, it’s important to know that regular expressions are not specific to python or Django. They have many uses across various areas of computer programming and software development.
WARNING
Regular expressions and their associated characters are universal, meaning they are the same across all programming languages.
Notice that the first path contains the URL string of menu_item/10
. This string is static and immutable, which means it has no possible numerical variations even if in the same format.
For example if you enter a URL such as menu_item/01
, it will not match this path and map to the view. As a result a 404 not found error message will be displayed.
You can accept all URLs in this format using the regular expression path function like in the second entry.
WARNING
Notice the character r at the beginning, this makes a row string which treats the back slashes symbols as literal characters and not escape characters.
Common symbols used
- ^ : Caret symbol used as the anchor at the start of the string, it can also be used for negation.
- & : Dollar symbol which is used as the anchor for the end of the string.
- [] : You use opening and closing square brackets to define a character set that matches any one of the characters present inside.
- {} : Opening and closing curly brackets are used to specify the exact number of proceeding characters.
- () : Opening and closing parenthesis are used for grouping parts of the RegEx.
Acceptable strings for this RegEx can be menu item forward slash followed by the range 1 to 99.
Regular expressions are extremely useful while creating you URLs, but at the same time they can often get complex. And this is especially true for regular expressions containing several special characters.
It’s common for aspiring developers to feel confused when first learning regular expressions. Sometimes a symbol can be used for one or more purposes or the same symbol can behave differently depending on the case. Getting familiar with their usage requires some practice and a little patience.
URL Namespacing and Views
This reading explains the use of named URLs in the URLconf
of a Django app and how the use of a namespace helps in resolving the same URL name in more than one app.
In each app, there is a urls.py
file that defines the list of URL patterns for that app. Each pattern is constructed by django.urls.path()
function. Its arguments are a URL path string, the name of the view function to be mapped to it and an optional argument name.
The following is the urls.py
of an app:
It is included in the project’s urlpatterns
.
Normally, the client’s request URL is mapped against the function so that the application flow is directed toward it.Â
The URL references used internally by the application are hard-coded strings.Â
For example, a form template’s action attribute points towards /demoapp/login
URL so that when the form is submitted, the login view mapped to this URL is invoked.
<form action='/demoapp/login', method='POST>
# ...
</form>
reverse() function
However, the hard-coded URLs make the application less scalable and difficult to maintain as the project grows. In such a case, you can obtain the URL from the name parameter used in the path()
function.
Start the Django shell.
Django’s reverse()
function returns the URL path to which it is mapped.
The problem comes when the view function of the same name is defined in more than one app. This is where the idea of a namespace
is needed.
Application namespace
The application namespace is created by defining app_name
variable in the application’s urls.py
and assigning it the name of the app. In the demoapp/urls.py
script, make the change using the following code:
The app_name
defines the application namespace so that the views in this app are identified by it.
To obtain the URL path of the index()
function, call the reverse()
function by prepending the namespace to it.
To appreciate the advantage of defining a namespace, add another app in the project, for example, newapp
. Provide an index()
view function in it and define app_name
in its URLConf
file (that is urls.py
).
Update the project’s urls.py
.
The reverse()
function is executed for index view in newapp
namespace.
You can see that Django differentiates between same-named URLs in multiple apps with application namespace.
Instance namespace
You can also use the namespace parameter in the include()
function while adding an app’s urlpattern
to that of a project.
This namespace is called the instance namespace
.
Using namespace in view
Suppose you want the user to be conditionally redirected to the login view from inside another view. You need to obtain the URL of the login view and send the control to it with HttpResponsePermanentRedirect
.
namespace in the url
tag
An HTML form is submitted to the URL specified in the action attribute.
The form will then be processed by the view mapped to this URL. However, as mentioned above, a hard-coded URL is not desired. Instead, use the url
tag of the Django Template Language. It returns the absolute path from the named URL.Â
Use the url
tag to obtain the URL path dynamically, as shown below:
Again, the login view may be present in multiple apps. Use the named URL qualified with the namespace to resolve the conflict.
The browser shows the login form as below:
Thus, the concept of namespace helps in resolving the conflict arising out of multiple apps under the same project having views of the same name.
You have covered some of the concepts here in line with the use of form templates in Django. If you have difficulty understanding some things, be assured it will be much more clear once you cover the topic of templates in this course.
In this reading, you further explored the concept of URL Namespacing and Views in Django.
Error Handling
An application will contain errors in some form no matter how much testing or QA is performed. This is not always directly related to incorrect code or syntax issues By their very nature networks are not always 100% reliable and things can occasionally go wrong as an aspiring developer.
More common status codes
Client Error
- 400 : which represents a bad request. This occurs when parameters passed in the request are not what the server may expect.
- 401 : which indicates that the user must log into an account before processing the request.
- 403 : indicating that the request was valid but that the Web server refuses to process it. This typically means that the user calling the resource does not have the required permissions to view the resource.
- 404 : indicates that the requested resource was not found on the web server. This typically happens when the resource cannot be located at the specified file path.
Server Error
Server or responses usually indicate a failure occurred on the web server while trying to process the request. This can mean many things. For example, the application has failed or is not running or the time limit on the calling request may have aborted due to the server taking a long time to respond
- 500 : internal server error which is a generic error status indicating that the server failed to process the request.
How django handles errors
Django handles all our cases by raising an exception which is invoked via an error handling view that you can configure. These are handling views are added to a separate views, That pie file that must be created at the project level to get applied across the project.
The views to use for these cases are specified by four variables. They are:
- handler400
- handler403
- handler404
- handler500
NOTE
It’s important to know that while you can use the default values and views for your projects, there may be times when you want to customize the look of these views to align with the style or theme of your site.
Further customization is possible by overriding the default values. Such values can be set in the root U R L configuration file of your project. It’s important to know that setting these variables in any other URL configuration file will have no effect.
The first is handler 400 by default. This is the bad request view. Next is handler 403 by default. This is the permission denied view Next is Handler 404 by default. This is the page not found view finally, handler 500 by default. This is the server error view.
The view function needs to accept the appropriate request argument and return the appropriate response. The custom views that you create using these handlers return different http response sub classes that handle different types of http responses.
- Class HttpResponseNotFound, Acts just like http response but uses a 404 status code
- Class HttpResponseBadRequest acts just like http response, but uses a 400 status code
- Class HttpResponseForbidden acts just like http response, but uses a 403 status code
- Class HttpResponseServerError acts just like http response, but uses a 500 status code
Handling Errors in Views
In a Django application, a view function is where all the processing is done.
It receives the request and formulates the response.
In this Reading, you’ll learn how Django handles runtime errors or exceptions.
The response from the view is an object of HttpResponse
. Its contents are also associated with a respective status code.
For example, status code 404 implies that the resource requested by the client cannot be found. Django has a generic HttpResponseNotFound
class. You can return its object to convey the appropriate message.
You can also return a HttpResponse
with the status code denoting the type of error.
The main difference in using HttpResponseNotFound
as opposed to HttpResponse
that must be understood is that Django internally sends an error code 404. The appropriate page for 404 can then be configured and rendered, else the browser displays its default 404 view.
A common cause of the 404 status code is the user entering an incorrect URL.
Django makes it easy to work with this error code.
Put a string argument inside the HttpResponseNotFound()
to view the error message. Instead, raise Http404
. Django displays a standard error page with the status.
(Instead, raise Http404
exception).
Consider the following scenario, where you have a Product
model in the app.
The user wants the details of a product with a specific Product ID.
In the following view function, id
is the parameter obtained from the URL.
It tries to determine whether any product with the given id is available. If not, the Http404
exception is raised.
Just like the HttpResponseNotFound
, there are a number of other predefined classes such as HttpResponseBadRequest
, HttpResponseForbidden
and so on.
Custom error pages
If you want to show your own error page whenever the user encounters a 404 error, you must create a 404.html page and put it in the project/templates folder.
You will learn more about how to do this later when you explore templates.
Displaying error messages in the browser
Usually, the Django development server is in DEBUG
mode, which shows the error’s traceback instead of the exception.
To render the custom exception message, the DEBUG variable in the project’s settings should be set to False.
Exception classes
Django’s exception classes are defined in the django.core.exceptions
module.Â
Some important exception types are:
ObjectDoesNotExist
: All the exceptions of theDoesNotExist
are inherited from this base exception.EmptyResultSet
: This exception is raised if a query does not return any result.FieldDoesNotExist
: This exception is raised when the requested field does not exist.
MultipleObjectsReturned
: When you expect a certain query to return only a single object, however multiple objects are returned. This is when you need to raise this exception.PermissionDenied
: This exception is raised when a user does not have permission to perform the action requested.
ViewDoesNotExist
: This exception is raised bydjango.urls
when a requested view does not exist, possibly because of incorrect mapping defined in theURLconf
.Â
When a certain view is called with a POST or PUT request, the request body is populated by the form data.Â
Django’s Form API defines various fields specific to the type of data stored. For example, you have EmailField
, FileField
, IntegerField
, MultipleChoiceField
.Â
These fields have built-in validators. The is_valid()
method returns True if the validations are passed. You can raise an exception if it returns False.
In addition to the exceptions defined in the core module, you can process the standard Python exceptions and the database-related exceptions.
In this reading, you learned how to handle errors inside the Django view.
Demo: Handle errors in views
Recall that Django displays a page not found error page when a URL cannot be matched. This default error page displays with some technical information for the developer, including the request method and request URL.
However, you usually do not want your end-users to access this type of information, as these types of error messages will mean nothing to them. Instead, you can create a custom view for the error page.
Let’s begin by running a server first, by typing python3managed.py run server. Next, open the local host URL in your browser and notice the default page loads. If you enter some URL, let’s say home. Notice that a page not found error page is displayed by default. The page contains some error information and a message stating; you’re seeing this error because you have DEBUG =True in the Django settings file. Change that to false, and Django will display a standard 404 page.
Debugging
Debugging is the process of handling errors in code.
In Django, debug mode is set to true by default, which displays detailed error pages during development.
To apply this change, open the settings.py
file under the my project and change the debug value to false.
WARNING
Additionally, you must add some value inside allowed host. In this example, add the star symbol to include all possible hosts.
Custom view for the Error
To do this, you must create a new file called views.py
at the project level. Once created, open the urls.py
file and update the code with the necessary imports and URL patterns. Additionally, you must add another URL pattern outside the URL patterns sequence.
Create the view location myproject.views.handler404
and assign it to a variable called handler404
.
Next, go to the views.py file inside the project folder and import HttpResponse
. Create a view with the name handler404 as referenced previously. Inside the function, pass the request object and an exception argument. Then return the HTTP response object with some text value such as 404 call on Page not Found.
Similarly, just as the code uses the HttpResponse
object, you can also use HttpResponseNotFound
. Different classes in Django represent different status codes. The HTTP response not found class represents status code 404 Page not Found.
TIP
It’s generally considered best practice to create a custom error page that’s easy to understand, consistent with the website’s branding, and directs users back to the homepage.
Class-based views
Organizing your code in a clean and easy to use manner is essential when working on a project. As the project grows, keeping code organized and well structured can be a challenge for developers.
To help overcome these challenges, developers often use frameworks and design patterns such as MVT. For example, with the Django framework, you can use views to present data to the end users.
In the background, the framework passes that HTTP request to your function expecting the HTTP response back. While this works for some use cases, developers often need a more robust solution for implementing more complicated application logic in a view.
To help with this, Django provides something called a class based view.
Features of class based views
Class based views allow you to use views as objects and offer an alternative to function based views. Remember that a view is callable in that it can take a request and return a response. This process works great for the HTTP protocol. When dealing with HTTP, you use specific methods for the different types of requests. Such as get, post, put and delete and these are the core CRUD operations for any web page.
If you use a function based view, you need to perform some conditional logic on the request method, like an if else statement. But class based views, uses a different approach than function based views. Instead of using conditional branching, such as if else statements, class based views respond to HTTP requests using class instance methods. Instance methods are default python methods, defined in classes that can access objects or instances of a class.
In a class based view, this can be simplified by adding different instance methods for the get and post requests. And these methods will implement the view logic independently.
Class based views, respond with different class instance methods to HTTP requests in place of writing conditional branches, such as using if else, statements inside the same function.
The advantage of using a class based view in this scenario, is that it allows you to remove the conditional logic to check the incoming request for the type of method. This simplifies the code and separates the logic, making it easy to understand.
Another helpful aspect is the ability to have object oriented techniques, such as mixins or multiple inheritance, which factor code into reusable components.
In Django, you can extend the functionality of class based views using mixins.
Mixins
Mixins are class based generic views that are flexible compared to their function based view equivalent. It can help to think of a mixin as a form of multiple inheritance.
Recall that inheritance as one of the core concepts of object oriented design or OOP. It allows you to derive one class from another for a hierarchy of classes with similar attributes. For example, suppose you have a class called food. Other classes that can inherit from this class could be appetizers, entree and desserts.
They are all types of food and would share a lot of common attributes. Some common mixins developers use are create, list, retrieve, update and delete.
- Use create to create a model instance
class MenuCreate(CreateView):
- Use list to list a query set
class MenuList(ListView):
- Use retrieve to retrieve a model instance
class MenuDetailView(ListView):
- Use update to update a model instance
class MenuUpdateView(UpdateView):
- Use delete to delete a model instance
class MenuDeleteView(DeleteView):
NOTE
It’s important to note that when using mixins, they can’t be all used together. And in some cases it can make your code harder to read. So, it’s best to use them wisely.
Additional resources
Here is a list of additional resources that may be helpful as you continue your learning journey.
The django.urls functions for use in URLconfs - official documentation
Render HTML Forms – GET and POST in Django
Previous one → 6.Requests and URLs | Next one → 8.Models & Migrations