Working on Django projects I find very often that many developers access the values that are defined in settings in this way
from django.conf import settings
my_value = settings.MY_SETTING
What happens if MY_SETTING has not been defined in settings.py? The code will raise an error and crash, of course. How can we make the code more reliable? We could try/except the code block that tries to read the value and maybe set a value if we get an exception, but this would not be a clean way to do this job.
A cleaner way to do it is to use getattr in this way:
from django.conf import settings
my_value = getattr(settings, 'MY_SETTING', 'my-default-value')
getattr will try to read MY_SETTING value from settings.py, if the value doesn’t exist my_value will be assigned with my-default-value.
To understand how a Django Middleware works we need to remember that the basic architecture of Django is composed by a request and a response. A middleware is something that stays in the middle. Let’s give a look to the next diagram, taken from official Django documentation:
Important things to know
There are four important things to know about middlewares:
- You need to write a class that just inherit from object
- The order where you place your middleware in settings.py is important: middlewares are processed from top to bottom during a request and from bottom to top during a response.
- You don’t need to implement all the available methods of a middleware. For example you can just implement process_request and process_template_response
- If you implement process_request and you decide to return an HttpResponse, all the other middlewares, views etc… will be ignored and only your response will be returned
Writing a middleware
In my example I wanted to implement a feature that saves the time when a request is made and the time when a request has been processed, then calculates the time delta and exposes this value in the context so that is accessible from our templates. How to implement a similar feature using a middleware? Here is my example:
from datetime import datetime
def process_request(self, request):
request._request_time = datetime.now()
def process_template_response(self, request, response):
response_time = request._request_time - datetime.now()
response.context_data['response_time'] = abs(response_time)
Please don’t care about how I calculated the time. I’m aware that there are better ways to do it, but I just wanted to keep it simple and show how to implement a simple middleware.
If you want to see a complete example of a project that includes and uses this middleware, here you can find the complete source code: https://github.com/andreagrandi/benchmark-middleware-example
This won’t be a full post, but just a quick note (probably the first one of a serie) about development with Django.
When we write a TestCase test, if we have defined a setUp method, it will be called before the execution of each test. One could think that the database is completely reset after each test, but this is not true (not like I was thinking). After each test, whatever we wrote on the database is rolled back. If we create a “Client” row (assuming we have a model called Clients) in our setUp, when we call it the second time the ID won’t be 1 as someone (me included) could expect. It will be 2 instead, because the database has not completely deleted and created from scratch.
This means that we can’t assume that our Client ID will always be 1 for each test and we should rather reference to it in a dinamic way like: self.client.id
This could be a trivial thing for many people but I was not 100% sure about this so I asked for a confirmation on #django IRC room and people (expecially apollo13) was kind enough to explain me how it works.