Model Setup for a Quiz Application with Django Rest Framework: PART ONE

Jayaike Ndu
CodeTensor
Published in
4 min readSep 17, 2019
Django Rest Framework + React + Redux

Consider taking a moment to follow me on Twitter :)

https://twitter.com/jayaikendu

WATCH THE UPDATED VERSION OF THIS TUTORIAL (WITH FRONTEND INTEGRATION) AS A VIDEO ON YOUTUBE https://www.youtube.com/watch?v=I4LEMajjdjA&list=PLOOcfkIFw3os58bzJjtUfcmRae_Ht_dFw

I strongly suggest you watch the youtube video as it is more current.

I am going to show you guys how to create a basic Quiz Application with cool functionalities using Django (Rest Framework). You can later integrate it with React and Redux.

I am going to break this up into 2 parts so I can explain it very well and this is Part One.

You can get this code on Github here.

Setting up the Django Environment

I assume you have Django installed, so first of all, we are going to create our project and environment. In your command prompt run

django-admin startproject quiz

You should now have a project called quiz…YIPPEE!! The first step is done.

Now, change into your project directory and run the following command to create your virtual environment — if you don’t have pipenv installed just run pip install pipenv, and the code below will work for you:

pipenv shell

Next, we need to install all our packages and dependencies

pipenv install django djangorestframework

Create the new quizzes app (while still in your root project directory):

python manage.py startapp quizzes

Don’t forget to add it to your installed apps

INSTALLED_APPS = [
‘django.contrib.admin’,
‘django.contrib.auth’,
‘django.contrib.contenttypes’,
‘django.contrib.sessions’,
‘django.contrib.messages’,
‘django.contrib.staticfiles’,
‘quizzes’, # ------- NEW
]

We are going to use Django’s default User model for authentication so as not to blur the focus of this tutorial.

Go into your quizzes apps models.py file and add the following code which I will explain now:

from django.db import models
from django.contrib.auth.models import User
from django.template.defaultfilters import slugify
from django.db.models.signals import post_save, pre_save
from django.dispatch import receiver
class Quiz(models.Model):
name = models.CharField(max_length=1000)
questions_count = models.IntegerField(default=0)
description = models.CharField(max_length=70)
created = models.DateTimeField(auto_now_add=True,null=True,blank=True)
slug = models.SlugField()
roll_out = models.BooleanField(default=False)
class Meta:
ordering = [‘created’,]
verbose_name_plural =”Quizzes”
def __str__(self):
return self.name
class Question(models.Model):
quiz = models.ForeignKey(Quiz, on_delete=models.CASCADE)
label = models.CharField(max_length=1000)
order = models.IntegerField(default=0)
def __str__(self):
return self.label
class Answer(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
text = models.CharField(max_length=1000)
is_correct = models.BooleanField(default=False)
def __str__(self):
return self.text
class QuizTakers(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
quiz = models.ForeignKey(Quiz, on_delete=models.CASCADE)
correct_answers = models.IntegerField(default=0)
completed = models.BooleanField(default=False)
timestamp = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.user.username
class Response(models.Model):
quiztaker = models.ForeignKey(QuizTakers, on_delete=models.CASCADE)
question = models.ForeignKey(Question, on_delete=models.CASCADE)
answer = models.ForeignKey(Answer,on_delete=models.CASCADE,null=True,blank=True)
def __str__(self):
return self.question.label
@receiver(post_save, sender=Quiz)
def set_default_quiz(sender, instance, created,**kwargs):
quiz = Quiz.objects.filter(id = instance.id)
quiz.update(questions_count=instance.question_set.filter(quiz=instance.pk).count())
@receiver(post_save, sender=Question)
def set_default(sender, instance, created,**kwargs):
quiz = Quiz.objects.filter(id = instance.quiz.id)
quiz.update(questions_count=instance.quiz.question_set.filter(quiz=instance.quiz.pk).count())
@receiver(pre_save, sender=Quiz)
def slugify_title(sender, instance, *args, **kwargs):
instance.slug = slugify(instance.name)

What I did there was to link all the models for the quizzes from the top.

The Quiz Model

I created the quiz model to store the name of the quiz and virtually all the data related to the quiz. I also gave an option of roll_out to allow you to edit the quiz without it appearing on the website.

The Questions Model

Each Question is linked to an individual Quiz in the sense that every question has its label ie. the question, and the quiz with which it belongs to. I hope that is clear.

The Answer Model

As we all know every question must have an answer, although you can notice that there is also an extra field called is_correct. That is to specify whether that is the actual correct answer or not.

The QuizTaker Model

Every time someone takes a quiz, a quiz taker instance is created to save which user took the test, what the user scored in terms of correct answers, and whether the user has completed the quiz or not.

The post-save and pre-save hooks

These are just to make sure that the name of the quiz gets slugified and that the questions_count in the quiz is always equal to the number of questions related to that quiz.

I hope I am not confusing you all.

Now you should make your migrations and migrate the data:

python manage.py makemigrations

then…..

python manage.py migrate

I am going to rush this part sooo…you can more or less copy and paste the codes.

Install nested_admin by running:

pipenv install django-nested-admin

Then add this to your INSTALLED_APPS

INSTALLED_APPS = [
‘django.contrib.admin’,
‘django.contrib.auth’,
‘django.contrib.contenttypes’,
‘django.contrib.sessions’,
‘django.contrib.messages’,
‘django.contrib.staticfiles’,
‘quizzes’,
'nested_admin' # ------- NEW
]

Add this to your admin.py

from django.contrib import admin
import nested_admin
from .models import Quiz, Question, Answer, Response, QuizTakers
class AnswerInline(nested_admin.NestedTabularInline):
model = Answer
extra = 4
max_num = 4
class QuestionInline(nested_admin.NestedTabularInline):
model = Question
inlines = [AnswerInline,]
extra = 19
class QuizAdmin(nested_admin.NestedModelAdmin):
inlines = [QuestionInline,]
class ResponseInline(admin.TabularInline):
model = Response
class QuizTakersAdmin(admin.ModelAdmin):
inlines = [ResponseInline,]
admin.site.register(Quiz, QuizAdmin)
admin.site.register(QuizTakers, QuizTakersAdmin)
admin.site.register(Response)

Then add this to your urls.py in the quiz project folder where the settings.py file is:

from django.urls import path, include #imported includeurlpatterns = [
path(‘admin/’, admin.site.urls),
path(‘nested_admin/’, include(‘nested_admin.urls’)), #NEWWWW!!
]

Create a superuser to access the admin site.

python manage.py createsuperuser

Run your server:

python manage.py runserver

Visit the admin section and you should see this:

Django Admin

Add some Quizzes, NOT QUIZTAKERS OR RESPONSES….Just Quizzes with Questions and Answers.

Part Two is about the Django Rest Framework setup.

Follow me on Instagram

https://www.instagram.com/jay._kay_/

NEXT TUTORIAL HERE

--

--

Jayaike Ndu
CodeTensor

Software Developer solving real-world problems with code. Founder of Squizel and Editor of CodeTensor