Model Setup for a Quiz Application with Django Rest Framework: PART ONE
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 receiverclass 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.nameclass 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.labelclass 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.textclass 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.usernameclass 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, QuizTakersclass AnswerInline(nested_admin.NestedTabularInline):
model = Answer
extra = 4
max_num = 4class QuestionInline(nested_admin.NestedTabularInline):
model = Question
inlines = [AnswerInline,]
extra = 19class QuizAdmin(nested_admin.NestedModelAdmin):
inlines = [QuestionInline,]class ResponseInline(admin.TabularInline):
model = Responseclass 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:
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