Home > front end >  How can I efficiently factor out similar contexts from multiple views in Django?
How can I efficiently factor out similar contexts from multiple views in Django?

Time:09-02

Suppose we have two or more views, where each view templates extends from base.html, and inside the base.html file are context variables project_name and company_name:

File base.html

<!DOCTYPE html>
<html>
  <head>
    <title>{{ project_name }}</title>
  </head>
  <body>
    {{ company_name }}
    {% block content %}{% endblock %}
  </body>
</html>

Then we would have to add the above-mentioned contexts to our views as follow:

File views.py

def view1(request)
    context = {
        "view1 data": "some data",
        "project_name": "Project Name",
        "company_name": "Company Name",
    }
    return render(request, "view1.html", context)


class View2(DetailView):
    template_name = "view2.html"
    model = SampleModel

    def get_context_data(self, **kwargs):
        context = super(View2, self).get_context_data(**kwargs)
        context["view2 data"] = "sample data"
        context["project_name"] = "Project Name"
        context["company_name"] = "Company Name"
        return context

How do we write an efficient code so that our views will look like as follows, i.e. the common contexts project_name and company_name are factored out somewhere else yet will still be displayed in the base.html?

Desired views.py

def view1(request)
    context = {
        "view1 data": "some data",
    }
    return render(request, "view1.html", context)


class View2(DetailView):
    template_name = "view2.html"
    model = SampleModel

    def get_context_data(self, **kwargs):
        context = super(View2, self).get_context_data(**kwargs)
        context["view2 data"] = "sample data"
        return context

Understandably, function-based views and class-based views may function differently so there may be different solutions to each of them.

CodePudding user response:

To my knowledge, I know there are approaches to achieve that more efficiently. But adding a context processor is the efficient for me.

So, the following code snippet may make understanding the process easier:

Create a new Python file in any of your app folders; preferably name it as 'context_processors.py'. In that 'context_processors.py' file you may write:

def any_function_name(request):
    any_dictionary_name = {
        "view1 data": "some data",
        "project_name": "Project Name",
        "company_name": "Company Name",
    }

    return any_dictionary_name

(Note: Like that, you can even write queryset to get any data and make it available globally)

Then go the main project's file settings.py:

TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
                'your_app_name.context_processors.any_function_name' #Add the file reference here
            ],
        },
    },
]

Afterwards, you can access your context data anywhere in the template like this:

<!DOCTYPE html>
<html>
    <head>
        <title>{{ project_name }}</title>
    </head>

    <body>
      {{ company_name }}
      {% block content %}{% endblock %}
    </body>
</html>
  • Related