Debugging Django applications
Debugging
Debugging is the process of identifying and isolating an error, finding the source, and deploying measures to solve the problem.
While making mistakes is a part of programming, correcting errors inside a web framework, such as Django can be particularly difficult.
Unlike errors occurring in a standalone file that can be easily spotted, web projects consists of several interlinked files and dependencies that can make troubleshooting challenging.
While debugging takes patience, it also helps build a better understanding of the internal working of an application.
Mistakes can happen in many forms and at any stage of the development process. These can include :
- missing adding a view
- creating incorrect templates
- missing import statements
- inaccessible resources such as model data
- or even missing a comma in some attributes passed inside a function
As a beginner, seeing the errors and having to troubleshoot can be intimidating. While observation and hands-on practice with web applications are the best means to overcome errors in Django projects, there are tools available that can speed up the process of getting a project up and running.
You already know how to raise a few errors using provided internal implementations. But there are unforeseen errors that occur that also needs to be attended to.
Django has a distinct debugger that appears in the form of a yellow page arrow. You may recall seeing the debug equals true flag on the homepage of the local host after running the server. The Django debugger is enabled by default, and settings for it an be found and modified inside the settings.py
file of your project.
While it is a useful component of development, the developers of Django recommend that it should never be used in the production environment. This is because it may expose internal file parts, as well as database and project configuration details to the end user using your website.
This can be prevented by changing the setting to debug equals false.
Other than the default debugger provided by Django, Django, as you know is written in Python and can easily integrate third party libraries that help in debugging.
Let’s now examine a few ways in which you can debug Django applications. This example uses the creating forms project demonstrated earlier.
Immediately, you’ll notice there is a 404 page not found error and this is because you haven’t configured the URL for the local host. Also, notice that this displays in the console in the logger.
NOTE
It’s important to know that the default Django implementation enlists all the steps that Django has performed after you run the command.
Let’s now go to the correct URL. Notice that the logs update at the bottom inside the console.
Now, open the forms.py file. Python specific errors will most likely occur in the console log. For example, if you comment out the shifts constant and save the file, notice an error log displays inside the console. The name error displays with the text, name shift is not defined. If you try to refresh the local host URL in the browser, notice that the page will not load.
However, some other errors are not that obvious. For example, remove the import you passed inside the log form and save the file. Notice that you do not get any error in the log. However, if you refresh the web page, notice that the template for the form disappears except for the submit button that was rendered using static HTML markup.
To prevent this from happening, always ensure you have the right imports and that you pass the correct arguments inside functions.
Let’s say you open the file, my template home.html
. Inside the file, remove the code for the CSRF token and save the file. If you go to the local host URL and reload the page, notice that the forms render correctly. Fill out the form and press the submit button. Notice that an error displays stating, forbidden CSRF verification failed. This error specifies that the CSRF token is missing, which is helpful for troubleshooting.
TIP
You can broadly say the yellow page errors are more specific to problems inside Django than Python code.
Now, let’s say you go to the files.py file again and misconfigure the template you are trying to render. Let’s say you call this home_page.html
and save it again. Once you go to a template page, you get an error such as template does not exist in the particular path.
First, it specifies the exception location, and you can get a hint from get template and how it is raised during form view.
Next, if you keep scrolling, you get a stack, which is called the trace back stack. It contains Python code in sequential order with a particular line highlighted, which will likely be the place of the error.
You can also convert this to switch to copy and paste view. When you change this, you get a much cleaner interface, mentioning all the details.
You can additionally click on, share this trace back on a public website, which when clicked, will take you to debase.com. This page displays convenient clipboard content that you can share on different forums.
If you scroll down further, there’s information about the dictionary containing all available HTTP header information called meta.
On further scrolling, you can find details inside the settings and all of these are potentially helpful.
TIP
Regarding debugging, you can never apply a one rule for all approach. With practice, the number of errors you encounter will slowly decrease. A systematic and patient approach in dealing with these projects is the best way forward.
Testing in Django
Testing is an important component in the software development lifecycle. While debugging is more driven towards removing the application’s errors and bugs, testing considers metrics for quality, reliability and performance.
Every language and framework has many testing options and developers make appropriate selections based on the project’s requirements.
Unit test
A popular method is unit testing, which you can use to isolate a function class or method and only test that piece of code.
When working with unit testing, you need the following baseline information:
First, the test targets granular features in your code, the smallest possible testable units. Then the output of the test will be pass fail or an error.
In Django. The unit test module uses a class based approach. You add the tests inside a class that inherits a class called test case from the Django test package.
Suppose you wrote a model called reservation and want to test it. First import that TestCase
class that inherits test case, then import the reservation model.
Once you create the tests, use the command :
Additionally, you can add specific configurations to run all tests within a specific package. For example, run the command:
To run a specific test case, use the command:
Our suppose you want to run a specific test method inside a test case, for example, a method to calculate the seat count. You can run the command like:
TIP
It’s important to know that developers generally add these test cases under one or more files created under specific app folders. In a small project it’s common for developers to name the file
tests.py
. In large projects that may contain multiple test files, it’s common for developers to use names liketest_models.py
andtest_views.py
.
Example
The ==auto_now
== field inside the booking time logs the system’s current time and is set to true.
setUpTestData
is a method present inside the test case that you use to add data inside the model. So in this example data is entered for the first name and the last name. It is important to know that booking time automatically updates as the auto_now
parameter is set to true.
You perform the check using the assert statements to check both the first name and last name are of the string data type.
WARNING
The final part of this step is to remember to add the
classmethod
decorator; Since this is a class method.
Sub-classing Generic Views
In this reading, you’ll learn about the class_based
generic views.
You can implement the view layer with function or class-based views in a Django application. You declare a class by extending the django.views.View
class and define get()
and post()
methods inside it to handle the HTTP requests. The URL pattern connects the path to the class with the as_view()
method of the View class.Â
A quick example of class view:
The URL pattern in urls.py
is updated as below:
Django provides class-based generic views to make the development process much easier and faster. In this reading, you’ll discover how the generic views are implemented.
The most frequently used generic views are:
- TemplateView
- CreateViewÂ
- ListView
- DetailViewÂ
- UpdateViewÂ
- DeleteView
- LoginView
Difference between Function View and generic view
Let’s take a simple example of rendering a Hello world template. You should render the template as the HTTP response – the return value of the function. The view function for this purpose would be as follows:
As you may have already learned, the app package folder exists inside the project’s outer container folder. The myapp
app is created in the Django project named myproject
.
In the myapp/urls.py
, define the URL pattern:
You can include the URL definitions of myapp
in the project’s URL configuration:
Use a TemplateView
class instead. Simply define a class extending it and set the template_name
attribute.
The corresponding URL pattern should incorporate this:
Advantage of function-based views
- Simple to implement.
- Easy to read.
- Explicit code flow.
- Straightforward usage of decorators.
- good for one-off or specialized functionality.
Disadvantages of function-based views
- Hard to extend and reuse the code.
- Handling of HTTP methods via conditional branching.
Advantages of Class-based views
- Code reusability.
- DRY — Using CBVs help to reduce code duplication.
- Code can be extended to include more functionalities.
- class with different methods for each http request instead of conditional branching statements inside a single function-based view.
- Built-in generic class-based views.
Disadvantages of Class-based views
- Harder to read.
- Implicit code flow.
- Use of view decorators require extra import or method override.
Requirements of a generic view
- If the view needs a model to be processed, it should be set as the value of model property of the view.
- Each type of view looks for a template name with
modelname
suffixed by the type of generic view. For example, for a list view processing employee model, Django tries to findemployee_list.html
. - The generic view is mapped with the URL with
as_view()
method of the View class.
Let’s now build a subclass for each of the respective generic view classes to perform CRUD operations on the Employee model:
CreateView
The CreateView
class automates the creation of a new instance of the model. To provide a create view, use the sub-class of CreateView
:
A model form based on the model structure is created by this view and passed to the employeeCreate.html
template:
The URL path is updated by mapping the "create/"
path to the as_view()
method of this class:
When the client visits this URL, they are presented with the form. The user fills and submits the employee details, which are saved in the Employee table.
ListView
Django’s django.views.generic.list
module contains the definition of ListView
class. Write its sub-class to render the list of model objects.
The EmployeeList
class is similar to the CreateView
sub-class except its base class.
The template required for this view must be named employee_list.html
. Django sends the model object in its context. Using the DTL loop syntax, you can display the list of employees:
If the user visits http://localhost:/8000/employees/list, the browser lists all the rows in the employee table.
DetailView
The generic DetailView
is found in the django.views.generic.detail
module. Now, create its sub-class, EmployeeDetail
(much the same way as EmployeeList
). Note that this view shows the details of an object whose primary key is passed as an argument in the URL. So, add the following path in the app’s URL pattern:
Again, the View object fetches the model instance and passes it as a context to the employee_detail.html
template, which displays its attributes with template syntax as follows:
Assuming the URL visited is /employees/1
, the Employee record with primary key=1 will be displayed.
UpdateView
This is another generic view, defined in django.views.generic.edit
module. It renders a form in which the new values of the model attributes can be submitted. Set the fields attribute to '__all__'
or to a list of updatable fields.
Since this view is intended to update the data of a given model instance, its URL path must be configured accordingly:
The example URL that invokes this view is /employees/1
.
The UpdateView
class renders the template with its name having update_form
as suffix:
DeleteView
Lastly, the generic view performs the delete operation on a model’s given instance. It is present when editing the sub-module of django.views.generic
module:
You need to pass the primary key of the Employee model to this. So, the URL path is set as:
The employee_confirm_delete.html
template asks for confirmation from the user before removing the model instance.
In this reading, you got to know about the class-based generic views to perform CRUD operations. Generic views are much easier to write than the function_based
view, although both have their own advantages and disadvantages.
Additional resources
Here is a list of resources that may be helpful as you continue your learning journey.
Testing overview – Django official
Django Advanced Testing topics
Add unit testing to your Django project
Adding Django apps – Extended information
PythonDjangoDatabaseTestDebugCRUD
Previous one → 13.Working with Templates | Next one → 1.Introduction to APIs