DEV Community

Ajeeb.K.P
Ajeeb.K.P

Posted on

My Worst CRUD Todo App : Django + Vue

Introduction

I'm not doing Django, Vue.js recently. So, need to write a simple blog post to refresh things. Will use Vue.js in script mode, like jQuery or other JS libs, without any build tools. And I'm not going to use any auth for keeping it simple

This blog post teaches neither Django nor Vue. Feel free to visit some resources below
https://docs.djangoproject.com/en/3.2/intro/tutorial01/
https://tutorial.djangogirls.org/en/
https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website

https://vuejs.org/v2/guide/
https://www.vuemastery.com/courses/intro-to-vue-js/vue-instance/

Disclaimer

This article does NOT follow any best practices. It teaches neither Django nor Vue. I'm just touching some basics to refresh my knowledge. That's the purpose of the article.

Django side

Install and start project

pip install django

mkdir django-vue-project && cd django-vue-project/ && django-admin startproject config .

python manage.py startapp app1

Add app1 to INSTALLED_APPS in settings.py

After your edits, it would be something like below

# config/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'app1',
]
Enter fullscreen mode Exit fullscreen mode

Follow https://github.com/adamchainz/django-cors-headers and configure cors.

Create Models

# app1/models.py
# Create your models here.
class Todo(models.Model):
    todo = models.TextField()
    is_done = models.BooleanField()
Enter fullscreen mode Exit fullscreen mode
python manage.py makemigrations
python manage.py migrate
Enter fullscreen mode Exit fullscreen mode

Enabling Django Admin, for Todo model

Create a superuser, so you can access admin pages. Note both username and password will be admin

python manage.py shell -c "from django.contrib.auth import get_user_model; User=get_user_model(); a=User.objects.create(username='admin'); a.set_password('admin'); a.is_superuser=True; a.is_staff=True; a.save()"
Enter fullscreen mode Exit fullscreen mode

Edit admin.py to enable Todo manipulation in django admin pages

# app1/admin.py
# Register your models here.
admin.site.register(Todo)
Enter fullscreen mode Exit fullscreen mode

Run django dev server

python manage.py runserver
Enter fullscreen mode Exit fullscreen mode

Visit following URL to create few Todo items
http://localhost:8000/admin/app1/todo/

Create List Todos End point

Create a ListView

# app1/views.py
from django.views import View
from django.http import JsonResponse
from app1.models import Todo

# Create your views here.
class TodoListView(View):

    def get(self, request):
        todos = list(Todo.objects.values_list('id', 'todo','is_done',))
        return JsonResponse(todos,safe=False)
Enter fullscreen mode Exit fullscreen mode

CreateView

Change app1/views.py as follows.

# app1/views.py
# ...
from app1.models import Todo
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
# ...
@method_decorator(csrf_exempt, name='dispatch')
class TodoCreateView(View):

    def post(self, request):
        data = {
            'todo' : request.POST.get('todo'),
            'is_done': False
        }
        todo = Todo(**data)
        todo.save()
        return JsonResponse({'status':'saved','id':todo.id})
Enter fullscreen mode Exit fullscreen mode

UpdateView

Again change app1/views.py

@method_decorator(csrf_exempt, name='dispatch')
class TodoUpdateView(View):

    def put(self, request, pk):
        todo = Todo.objects.get(pk=pk)

        # Workaround
        # https://dzone.com/articles/parsing-unsupported-requests-put-delete-etc-in-dja
        request.method = "POST"
        request._load_post_and_files()
        request.PUT = request.POST
        # End Workaround

        todo.todo= request.PUT.get('todo')
        todo.save()
        return JsonResponse({'status':'saved','id':todo.id})
Enter fullscreen mode Exit fullscreen mode

DeleteView

Change app1/views.py

@method_decorator(csrf_exempt, name="dispatch")
class TodoDeleteView(View):
    def dispatch(self, request, *args, **kwargs):
        # https://micropyramid.com/blog/introduction-to-django-class-based-views/
        pk = kwargs.get("pk")
        return self.delete(request, pk)

    def delete(self, request, pk):

        # Workaround
        # https://dzone.com/articles/parsing-unsupported-requests-put-delete-etc-in-dja
        request.method = "POST"
        request._load_post_and_files()
        request.DELETE = request.POST
        # End Workaround

        todo_qs = Todo.objects.filter(pk=pk)
        is_todo_exists = todo_qs.exists()
        if is_todo_exists:
            todo = todo_qs.delete()
            return JsonResponse(
                {"status": "deleted"}
            )
        else:
            return JsonResponse({"status": "failed", "message": "deletion failed"})

Enter fullscreen mode Exit fullscreen mode

Vue Js Code

Just copy pasted the code here

    var headers = { 'Content-Type': 'multipart/form-data' }
    var app = new Vue({
        el: '#app',
        data: {
            message: 'hello world',
            todos: [
                {
                    pk: 1,
                    todo: 'todo1',
                    is_done: false,
                },
                {
                    pk: 2,
                    todo: 'todo2',
                    is_done: false,
                },
                {
                    pk: 1,
                    todo: 'todo3',
                    is_done: false,
                },
            ],
            todo: null,
            pk: null,
        },
        methods: {
            reverseMessage: function () {
                this.message = this.message.split('').reverse().join('')
            },
            loadData: function () {
                var that = this
                axios.get('http://localhost:8000/').then(function (response) {
                    console.log(response)
                    that.todos = response.data
                })
            },
            saveThisTodo: function () {
                var that = this
                var todoData = new FormData();
                todoData.append('todo', this.todo)
                axios.post('http://localhost:8000/api/todo/create/', todoData, headers).then(function (response) {
                    console.log(response)
                    console.log('Saved')
                    that.loadData()
                })
            },
            updateTodo: function () {
                var todoData = new FormData();
                todoData.append('todo', this.todo)
                var that = this
                axios.put('http://localhost:8000/api/todo/update/' + this.pk, todoData, headers).then(function (response) {
                    console.log(response)
                    console.log('Updated')
                    that.loadData()
                })
            },
            editTodo: function (item) {
                console.log('Oh yeah: its time for edit')
                this.todo = item.todo
                this.pk = item.pk
            },
            deleteTodo: function (item) {
                var that = this
                axios.delete('http://localhost:8000/api/todo/delete/' + item.pk, headers).then(function (response) {
                    console.log(response)
                    console.log('Saved')
                    that.loadData()
                })
            }
        },
        mounted: function () {
            this.loadData()
        }
    })
Enter fullscreen mode Exit fullscreen mode

Conclusion

This blog post only shares the distant glimpses of what I have done. To get full idea, visit github repo here https://github.com/ajeebkp23/worst-crud-todo-app-vue-django

Top comments (0)