Introduction
To-do List is a pretty basic example app that is often done as one of the first projects, today we will make it a little more interesting by using few interesting technologies.
As the backend we will use Django and Django Rest Framework, and Alpine.js + Axios to glue it all together easily on the frontend.
What is Alpine.js
A pretty new lightwave framework inspired by Vue.js created last year by Caleb Porzio it gives us reactivity and declarativity of React and Vue, while keeping it light, and in the DOM. It’s described as TailwindCSS for JS. And I pretty much agree with that, using it together with Tailwind is a great boost to productivity when doing front-end because you can stay in one HTML file, and keep writing HTML, CSS, and js.
Axios
It’s an asynchronous HTTP client for JS.
Here is a link to finished project GitHub repo
Starting the app
Let’s start by creating a new virtual environment for our project, and installing required packages, then create a new Django project, and a lists app
pip install Django
pip install djangorestframework
django-adimn startproject todo_list
cd todo_list
django-admin startapp lists
Then go to settings.py and add lists
and django rest framework app to INSTALLED_APPS
INSTALLED_APPS = [
...
‘rest_framework’,
‘lists’,
]
Creating App Models
Let’s create db models for our To-Do App. We are going to define 2 models, a List Model, and a Task model, Each user can create as many lists as he/she wants, and then add multiple tasks to each list.
from django.contrib.auth.models import User
from django.db import models
class List(models.Model):
title = models.CharField(max_length=75)
user = models.ForeignKey(User,
on_delete=models.CASCADE,
related_name=‘lists’)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Task(models.Model):
parent_list = models.ForeignKey(List,
on_delete=models.CASCADE,
related_name=‘tasks’)
title = models.CharField(max_length=75)
completed = models.BooleanField(default=False,
blank=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
We created a List
model with the title field and relation to the user who created the list.
The Task
model, has a relation to List
object, title, and boolean for the complete status of the task.
Also for both models also 2 DateTime fields for cerated and updated times.
Go to the admin.py file and register the models in the admin panel
from django.contrib import admin
from .models import List, Task
admin.site.register(List)
admin.site.register(Task)
Run the makemigrations
and migrate
commands.
python manage.py makemigrations
python manage.py migrateapi
Create API
Create Serializers
Inside the lists app create a new python package (new directory with an empty __init__.py
file), and call it api
. There create a file serializers.py, views.py
, urls.py files inside. Go to serialziers.py and create serializers for the models.
from rest_framework import serializers
from ..models import List, Task
class TaskSerializer(serializers.ModelSerializer):
class Meta:
model = Task
fields = (‘title’, ‘completed’, ‘parent_list’)
class ListSerializer(serializers.ModelSerializer):
tasks = TaskSerializer(many=True, read_only=True)
class Meta:
model = List
fields = (‘title’, ‘tasks’)
Create Viewsets
Now we will create viewsets, that will automatically provide us with Create, Read, Update, and Delete endpoints (CRUD), so we can avoid repetition and writing them for each model. In views.py file create viewsets.
from rest_framework import viewsets
from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAuthenticated
from .serializers import TaskSerializer, ListSerializer
from ..models import Task, List
class ListViewSet(viewsets.ModelViewSet):
queryset = Task.objects.all()
serializer_class = ListSerializer
authentication_classes = [SessionAuthentication]
permission_classes = [IsAuthenticated]
def get_queryset(self):
user = self.request.user
return List.objects.filter(user=user)
def create(self, request, *args, **kwargs):
serializer = ListSerializer(data=request.data)
if serializer.is_valid():
serializer.save(user=request.user)
return Response(serializer.validated_data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class TaskViewSet(viewsets.ModelViewSet):
queryset = Task.objects.all()
serializer_class = TaskSerializer
authentication_classes = [SessionAuthentication]
permission_classes = [IsAuthenticated]
def get_queryset(self):
user = self.request.user
return Task.objects.filter(parent_list__user=user)
#django #axios #alpine #tailwindcss #developer