1

The application is intended to serve a single user. I am attempting to stuff multiple model classes objects inside of the get_context_data method. My issue is when I go to call the context variable in my template all I get is the query set. If i call a specific item in the query set all I see is a location in memory. If I call the context varriable 'data' in a for loop inside of the template I get nothing at all. According to the django docs, this logic should work. What step am i missing? Or would I be better served using a function based view?

my model

class backend(models.Model):
    lang1 = models.CharField(max_length=50)
    lang2 = models.CharField(max_length=50)
    lang3 = models.CharField(max_length=50)
    

    def __str__(self):
        return 'Backend Language'

class frontend(models.Model):
    lang1 = models.CharField( max_length=50)
    lang2 = models.CharField(max_length=50)
    lang3 = models.CharField(max_length=50)
    
    def __str__(self):
        return 'Frontend Language'
    
class datalayer(models.Model):
    lang1 = models.CharField( max_length=50)
    lang2 = models.CharField(max_length=50)
    lang3 = models.CharField(max_length=50)

    def __str__(self):
        return 'Database Language'

my view


from django.shortcuts import render
from django.views.generic import View, TemplateView, ListView
from cbvapp.models import backend, frontend, datalayer

class Index(ListView):
    template_name = 'index.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['data'] = [backend.objects.all(),
                            datalayer.objects.all(),
                            frontend.objects.all()]
        return context
ChillieCode
  • 139
  • 1
  • 8

1 Answers1

2

My issue is when I go to call the context variable in my template all I get is the query set.

This is because, in your context data (specifically ['data']), all the objects are a queryset as you used .objects.all(). I know two solutions that could work: one is to return them separately if they are not related, and the other is to use a zip function.

Return data separately

Naive, but works if your data is simple, meaning that they are irrelevant to each other.

def get_context_data(self, **kwargs):
    context = super().get_context_data(**kwargs)
    context['backend'] = backend.objects.all()
    context['datalayer'] = datalayer.objects.all()
    context['frontend'] = frontend.objects.all()
    return context

Bundle data together

Use this if you want your context to show up together.

def get_context_data(self, **kwargs):
    context = super().get_context_data(**kwargs)

    back = list(backend.objects.all())
    datal = list(datalayer.objects.all())
    front = list(frontend.objects.all())
    context['data'] = zip(back, data1, front)    # pairs data up, returns 2D array

    return context

So let's say you have these

back = [a, b, c]
datal = [d, e, f]
front = [g, h, i]

When you zip them together you'll get

zipped = [[a, d, g], [b, e, h], [c, f, i]]

P.S. according to this thread, you can cast querysets to a list

crimsonpython24
  • 2,223
  • 2
  • 11
  • 27
  • The zip has downside ***in this particular case***. What if the length of the queryset is different? – JPG Aug 03 '20 at 03:09
  • 1
    I do remember a tool `itertools.zip_longest` when the lengths are different: it substitutes `None` for values that are shorter. Here are the [docs](https://docs.python.org/3/library/itertools.html#itertools.zip_longest) – crimsonpython24 Aug 03 '20 at 03:21