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.