A better way for passing Django context

I like Python as a language and Django as a framework. They are super practical and let you create incredible things in no time.

But if there's one thing I dislike is the use of dictionaries everywhere. I am mainly referring to the Context object that requires a dictionary to be passed to render a Django template. I find this to be extremely ugly. For instance, if you need to render the template in multiple places, you would need to repeat the dictionary keys when constructing the dictionary. You could save the dictionary keys in some variables and use those in the dictionary, but this is not that elegant.

The solution I prefer in this situation is to use data classes for each template, and convert that data class to a dictionary when needed. With this approach, I get the type of safety, elegance, and DRY (Don't Repeat Yourself) principle quickly and easily.

For instance, take this use case:

[...]
return render(request,
              template_name='template.html',
              context={
                  'key1': 'value1',
                  'key2': 42
              })

If you have to use this template in another View, then you would need to repeat those keys. Instead, you could create a data class for the context and convert that to a dict when needed:

@dataclass # 1.
class MyViewContext:
    key1: str # 2.
    key2: int 

    def dict(self): # 3.
        return asdict(self) 

[...]
return render(request,
              template_name='template.html',
              context=MyViewContext(key1='value1', key2=42).dict()) # 4.
  1. Data classes were introduced in Python 3.7. A data class comes with the basic functionality needed to initialize and compare a class. Its aim is just to contain data in an object-oriented manner.
  2. Data types are optional but highly recommended.
  3. asdict converts a data class into a dictionary with the variable names as keys. Here we create a convenience member method to make that conversion.
  4. Initialize the data class, and convert that to a dictionary!

Hopefully, you would prefer this approach when creating context objects for rendering Django templates.

Happy coding!