Today, I wanted to add a view which outputs the result of a Django queryset as a JSON array.

Sounds simple, but it took me a couple of minutes to figure out how to do it properly:

from .models import *
 
from django.http import JsonResponse
 
def covid19_json(request):
data = CaseState.objects.values()
return JsonResponse(list(data), safe=False)

The things which are important:

  • You need to call .values() to get the actual queryset result
  • You then need to run it through list() to get it as a list
  • Lastly, you need to return a JsonResponse object with the parameter safe set to False to output it. The safe parameter is required as you're outputting a non-dictionary object.

If you want more control over how your models are converted to JSON, you can define for example a method called json on your model class:

from django.db import models
 
class CaseState(models.Model):
date = models.DateField(primary_key=True)
country = models.CharField(max_length=255)
cases = models.IntegerField(blank=True, default=0)
today_cases = models.IntegerField(blank=True, default=0)
deaths = models.IntegerField(blank=True, default=0)
today_deaths = models.IntegerField(blank=True, default=0)
recovered = models.IntegerField(blank=True, default=0)
active = models.IntegerField(blank=True, default=0)
critical = models.IntegerField(blank=True, default=0)
cases_per_one_million = models.IntegerField(blank=True, default=0)
deaths_per_one_million = models.IntegerField(blank=True, default=0)
 
def json(self):
return {
'date': str(self.date),
'country': self.country,
'cases': self.cases,
}

Then, do the following in the view function:

import json
 
from .models import *
 
from django.http import HttpResponse
 
def covid19_json(request):
data = [i.json() for i in CaseState.objects.all()]
return HttpResponse(json.dumps(data), content_type="application/json")

The second approach doesn't require a one on one match between the model and the json output.