Back to Blog
Tutorial

How to Build a Quiz App with Django and QuizAPI

Step-by-step guide to building a quiz application with Django using the QuizAPI REST API. Fetch questions, render a quiz UI, and submit scores.

Bobby Iliev2026-04-088 min read

Overview

In this tutorial, you'll build a Django quiz application that pulls questions from QuizAPI and lets users take quizzes directly in your Django app. By the end, you'll have a working quiz page that fetches questions, tracks answers, and submits scores.

Prerequisites

  • Python 3.10+
  • Django 5.x installed
  • A QuizAPI account and API key (get one free at quizapi.io)
  • Basic familiarity with Django views and templates

Project Setup

Create a new Django project and app:

django-admin startproject quizproject
cd quizproject
python manage.py startapp quizzes
pip install requests

Add quizzes to INSTALLED_APPS in settings.py, and add your API key:

# settings.py
QUIZAPI_KEY = "your-api-key-here"
QUIZAPI_BASE_URL = "https://quizapi.io/api/v1"

Fetching Quizzes from the API

Create a service layer to talk to QuizAPI:

# quizzes/services.py
import requests
from django.conf import settings

def get_quizzes(limit=10, category=None):
    """Fetch published quizzes from QuizAPI."""
    params = {"limit": limit}
    if category:
        params["category"] = category

    response = requests.get(
        f"{settings.QUIZAPI_BASE_URL}/quizzes",
        headers={"Authorization": f"Bearer {settings.QUIZAPI_KEY}"},
        params=params,
    )
    response.raise_for_status()
    return response.json()["data"]

def get_quiz_questions(quiz_id):
    """Fetch questions for a specific quiz."""
    response = requests.get(
        f"{settings.QUIZAPI_BASE_URL}/questions",
        headers={"Authorization": f"Bearer {settings.QUIZAPI_KEY}"},
        params={"quizId": quiz_id},
    )
    response.raise_for_status()
    return response.json()["data"]

Building the Views

# quizzes/views.py
from django.shortcuts import render
from .services import get_quizzes, get_quiz_questions

def quiz_list(request):
    quizzes = get_quizzes(limit=20)
    return render(request, "quizzes/list.html", {"quizzes": quizzes})

def quiz_play(request, quiz_id):
    questions = get_quiz_questions(quiz_id)
    return render(request, "quizzes/play.html", {
        "quiz_id": quiz_id,
        "questions": questions,
    })

def quiz_results(request):
    if request.method != "POST":
        return render(request, "quizzes/results.html", {"score": 0, "total": 0})

    # Calculate score from submitted answers
    score = 0
    total = 0
    for key, value in request.POST.items():
        if key.startswith("question_"):
            total += 1
            # value is the answer ID, check if it matches the correct answer
            correct = request.POST.get(f"correct_{key}", "")
            if value == correct:
                score += 1

    percentage = round((score / total) * 100) if total > 0 else 0
    return render(request, "quizzes/results.html", {
        "score": score,
        "total": total,
        "percentage": percentage,
    })

Creating the Templates

Quiz List

<!-- templates/quizzes/list.html -->
{% extends "base.html" %}
{% block content %}
<h1>Available Quizzes</h1>
<div class="quiz-grid">
  {% for quiz in quizzes %}
  <div class="quiz-card">
    <h2>{{ quiz.title }}</h2>
    <p>{{ quiz.description }}</p>
    <span class="badge">{{ quiz.difficulty }}</span>
    <span class="badge">{{ quiz.questionCount }} questions</span>
    <a href="{% url 'quiz_play' quiz.id %}" class="btn">Play Quiz</a>
  </div>
  {% endfor %}
</div>
{% endblock %}

Quiz Play

<!-- templates/quizzes/play.html -->
{% extends "base.html" %}
{% block content %}
<form method="post" action="{% url 'quiz_results' %}">
  {% csrf_token %}
  {% for q in questions %}
  <div class="question-card">
    <h3>{{ forloop.counter }}. {{ q.text }}</h3>
    {% for answer in q.answers %}
    <label class="answer-option">
      <input type="radio"
             name="question_{{ q.id }}"
             value="{{ answer.id }}"
             required>
      {{ answer.text }}
    </label>
    {% endfor %}
    <!-- Store correct answer ID in a hidden field -->
    {% for answer in q.answers %}
      {% if answer.isCorrect %}
      <input type="hidden"
             name="correct_question_{{ q.id }}"
             value="{{ answer.id }}">
      {% endif %}
    {% endfor %}
  </div>
  {% endfor %}
  <button type="submit" class="btn">Submit Answers</button>
</form>
{% endblock %}

URL Configuration

# quizzes/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path("", views.quiz_list, name="quiz_list"),
    path("play/<str:quiz_id>/", views.quiz_play, name="quiz_play"),
    path("results/", views.quiz_results, name="quiz_results"),
]
# quizproject/urls.py
from django.urls import path, include

urlpatterns = [
    path("quizzes/", include("quizzes.urls")),
]

Running the App

python manage.py runserver

Visit http://localhost:8000/quizzes/ to see your quiz list. Click any quiz to play it, and submit your answers to see your score.

Next Steps

  • Add user authentication to save scores per user
  • Cache API responses with Django's cache framework to reduce API calls
  • Add category filtering to the quiz list
  • Style with Tailwind CSS or Bootstrap for a polished look
  • Use the QuizAPI leaderboard endpoint to show high scores

Resources

Stay Updated

Get the latest tutorials and API tips delivered to your inbox.

No spam, unsubscribe anytime.

Enjoyed this article?

Share it with your team or try our quiz platform.