Did you face the problem of fetching data from multiple models in a single view while developing your Django application?

For example, Think of showing all the cars owned by a person in the person’s detail view. The generic DetailView provides the Person’s object to the context, but how do we get information of cars in that template? In this article, we will find out the solution.

The solution is to override the get_context_data() method of generic views. This method returns a dictionary. This method is used to populate the ‘context’ (can be named anything) dictionary to use as the template context.

Our Models
from django.db import models


class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

    def __str__(self):
        return f'{self.first_name} {self.last_name}'    

class Car(models.Model):
    owner=models.ForeignKey(Person,on_delete=           models.SET_NULL, null=True)
    name = models.CharField(max_length=30)

    def __str__(self):
        return self.name
View
from django.views.generic import DetailView
from person.models import Person


class PersonDetails(DetailView):
    model = Person
    template_name = 'details.html'
    
    def get_context_data(self, **kwargs):
        # Call the base implementation(from parent  class) first to get a context

        context = super().get_context_data(**kwargs)
        # Add a QuerySet in the 'context' of the cars owned by this person

        context['cars'] = Car.objects.filter(owner =self.id)
        return context

Here we have called the get_context_data() method of our Super Class and assigned it to the variable context. The method will merge the context data of parent class with child class. If you check the type(context), you will see that it is a dictionary. Then, we filtered data from the ‘Car’ model and stored the data in our ‘context’ dictionary against the key ‘cars’. You may get confused that wherefrom the ‘pk’ is coming. Let me make you clear. We have passed a value in our URL.

path('person/<int:pk>/', PersonDetails.as_view(), name='person-detail-view'),

Our method takes this ‘pk’ in **kwargs(it is a dictionary). Then we have accessed the value of that dictionary. After that, we returned to the whole context. Now, each object of our PersonDetailView class has a property named ‘get_context_data()’ which returns a dictionary. As we have told you before, the ‘cars’ is a key of the context dictionary which is a queryset. We can access the elements of the queryset in our template by looping over them.

Template
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h2><a href="{{object.get_absolute_url}} "> {{object.first_name}}</a></h2>
    <h4>Cars Owned By {{object.full_name}}</h4>

        {% for car in cars %}
        <h4>{{car.name}}</h4>
        {% endfor %}
</body>
</html>
Output
Output

You can see everything is working fine. We have fetched data from two models and sent them wrapping in a dictionary named ‘context’. You can name whatever you want and also can fetch data from any number of models.

+ posts

Author | Python-Django Developer

+ posts

Full-stack Developer (Python | Django | React | React-Native | Angular | Vue)