From 1b9fcf76b7698abf8c58bde04a7e94e45de0ca17 Mon Sep 17 00:00:00 2001 From: rafa Date: Wed, 22 Oct 2025 13:15:42 +0100 Subject: [PATCH] finish todolist app and adjust docker envoirnment --- backend/.gitignore | 5 +- backend/Dockerfile | 7 +- backend/backend/settings.py | 5 +- backend/backend/urls.py | 7 +- backend/entrypoint.sh | 7 ++ backend/package.json | 6 ++ backend/templates/base.html | 41 ++++++++++++ backend/todolist/admin.py | 3 + backend/todolist/forms.py | 13 ++++ backend/todolist/models.py | 8 +++ .../todolist/templates/todolist/create.html | 59 ++++++++++++++++ backend/todolist/templates/todolist/edit.html | 67 +++++++++++++++++++ backend/todolist/templates/todolist/list.html | 43 ++++++++++++ .../todolist/todo_confirm_delete.html | 22 ++++++ backend/todolist/urls.py | 7 +- backend/todolist/views.py | 54 ++++++++++++++- compose.yaml | 7 ++ 17 files changed, 352 insertions(+), 9 deletions(-) create mode 100644 backend/entrypoint.sh create mode 100644 backend/package.json create mode 100644 backend/templates/base.html create mode 100644 backend/todolist/forms.py create mode 100644 backend/todolist/templates/todolist/create.html create mode 100644 backend/todolist/templates/todolist/edit.html create mode 100644 backend/todolist/templates/todolist/list.html create mode 100644 backend/todolist/templates/todolist/todo_confirm_delete.html diff --git a/backend/.gitignore b/backend/.gitignore index 688f8d9..9e90ab4 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -3,4 +3,7 @@ **/__pycache__/** -**/migrations/** \ No newline at end of file +**/migrations/** + +node_modules/ +package-lock.json \ No newline at end of file diff --git a/backend/Dockerfile b/backend/Dockerfile index 3b8058e..0d499ed 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -2,6 +2,11 @@ FROM python:3.13-bookworm RUN useradd -m django +RUN apt update -y && apt upgrade -y + +RUN wget https://nodejs.org/dist/v22.21.0/node-v22.21.0-linux-x64.tar.xz +RUN tar -xvf node-v22.21.0-linux-x64.tar.xz +RUN cp -r node-v22.21.0-linux-x64/* /usr/local WORKDIR /app @@ -12,4 +17,4 @@ COPY --chown=django . . USER django:django -CMD ["python", "manage.py", "runserver" , "0.0.0.0:8000"] +ENTRYPOINT ["/bin/bash", "entrypoint.sh"] diff --git a/backend/backend/settings.py b/backend/backend/settings.py index b04bf50..bdb7643 100644 --- a/backend/backend/settings.py +++ b/backend/backend/settings.py @@ -56,7 +56,7 @@ ROOT_URLCONF = 'backend.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], + 'DIRS': [ BASE_DIR / 'templates' ], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ @@ -121,6 +121,9 @@ USE_TZ = True # https://docs.djangoproject.com/en/5.2/howto/static-files/ STATIC_URL = 'static/' +STATICFILES_DIRS = [ + BASE_DIR / "node_modules", +] # Default primary key field type # https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field diff --git a/backend/backend/urls.py b/backend/backend/urls.py index 87b6e43..314789c 100644 --- a/backend/backend/urls.py +++ b/backend/backend/urls.py @@ -16,8 +16,11 @@ Including another URLconf """ from django.contrib import admin from django.urls import path, include +from django.conf.urls.static import static +from django.conf import settings + urlpatterns = [ - path("todolist/", include("todolist.urls")), + path("", include("todolist.urls")), path('admin/', admin.site.urls), -] +] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) diff --git a/backend/entrypoint.sh b/backend/entrypoint.sh new file mode 100644 index 0000000..af72de9 --- /dev/null +++ b/backend/entrypoint.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +npm install + +python manage.py makemigrations todolist +python manage.py migrate +python manage.py runserver 0.0.0.0:8000 \ No newline at end of file diff --git a/backend/package.json b/backend/package.json new file mode 100644 index 0000000..ad0d0ab --- /dev/null +++ b/backend/package.json @@ -0,0 +1,6 @@ +{ + "dependencies": { + "bootstrap": "^5.3.8", + "bootstrap-icons": "^1.13.1" + } +} diff --git a/backend/templates/base.html b/backend/templates/base.html new file mode 100644 index 0000000..d2cc847 --- /dev/null +++ b/backend/templates/base.html @@ -0,0 +1,41 @@ +{% load static %} + + + + + + + + + {% block extra_css %}{% endblock %} + {% block title %}Todo List{% endblock %} + + +
+ + + + {% block content %}{% endblock %} +
+ + + {% block extra_js %}{% endblock %} + + \ No newline at end of file diff --git a/backend/todolist/admin.py b/backend/todolist/admin.py index 8c38f3f..bc4a2a3 100644 --- a/backend/todolist/admin.py +++ b/backend/todolist/admin.py @@ -1,3 +1,6 @@ from django.contrib import admin +from .models import Todo # Register your models here. + +admin.site.register(Todo) diff --git a/backend/todolist/forms.py b/backend/todolist/forms.py new file mode 100644 index 0000000..e0ad799 --- /dev/null +++ b/backend/todolist/forms.py @@ -0,0 +1,13 @@ +from django.forms import ModelForm +from .models import Todo + +class TodoForm(ModelForm): + class Meta: + model = Todo + fields = ['title'] + +class TodoEditForm(ModelForm): + class Meta: + model = Todo + fields = ['title', 'completed'] + \ No newline at end of file diff --git a/backend/todolist/models.py b/backend/todolist/models.py index 71a8362..ff1e1fb 100644 --- a/backend/todolist/models.py +++ b/backend/todolist/models.py @@ -1,3 +1,11 @@ from django.db import models + # Create your models here. + +class Todo(models.Model): + title = models.CharField(max_length=200) + completed = models.BooleanField(default=False) + + def __str__(self): + return self.title \ No newline at end of file diff --git a/backend/todolist/templates/todolist/create.html b/backend/todolist/templates/todolist/create.html new file mode 100644 index 0000000..2e0ac34 --- /dev/null +++ b/backend/todolist/templates/todolist/create.html @@ -0,0 +1,59 @@ +{% extends "base.html" %} + + +{% block title %} + Create Todo +{% endblock title %} + + + +{% block content %} + +
+

Create Todo

+ +
+ {% csrf_token %} +
+ + +
+ This field is required +
+ {% if form.title.errors %} +
+ {{ form.title.errors }} +
+ {% endif %} +
+ + +
+ +
+ +{% endblock %} + +{% block extra_js %} + + + +{% endblock %} \ No newline at end of file diff --git a/backend/todolist/templates/todolist/edit.html b/backend/todolist/templates/todolist/edit.html new file mode 100644 index 0000000..a920cb7 --- /dev/null +++ b/backend/todolist/templates/todolist/edit.html @@ -0,0 +1,67 @@ +{% extends "base.html" %} + + +{% block title %} + Edit Todo +{% endblock title %} + + + +{% block content %} + +
+

Edit Todo

+ +
+ {% csrf_token %} +
+ + +
+ This field is required +
+
+ +
+ + +
+ This field is required +
+ {% if form.completed.errors %} +
+ {{ form.completed.errors }} +
+ {% endif %} +
+ + +
+ +
+ +{% endblock %} + +{% block extra_js %} + + + +{% endblock %} \ No newline at end of file diff --git a/backend/todolist/templates/todolist/list.html b/backend/todolist/templates/todolist/list.html new file mode 100644 index 0000000..904ad29 --- /dev/null +++ b/backend/todolist/templates/todolist/list.html @@ -0,0 +1,43 @@ +{% extends "base.html" %} + +{% block content %} + +
+
+
+

Todo List

+
+ +
+ + +
+ +{% endblock %} diff --git a/backend/todolist/templates/todolist/todo_confirm_delete.html b/backend/todolist/templates/todolist/todo_confirm_delete.html new file mode 100644 index 0000000..f84d17b --- /dev/null +++ b/backend/todolist/templates/todolist/todo_confirm_delete.html @@ -0,0 +1,22 @@ +{% extends "base.html" %} + +{% block title %} + Delete {{ object }} +{% endblock title %} + +{% block content %} + +
+
{% csrf_token %} + +
+
+ +{% endblock content %} \ No newline at end of file diff --git a/backend/todolist/urls.py b/backend/todolist/urls.py index ae5a309..97288ee 100644 --- a/backend/todolist/urls.py +++ b/backend/todolist/urls.py @@ -1,7 +1,10 @@ from django.urls import path -from . import views +from .views import TodoListView, TodoCreateView, TodoEditView, TodoDeleteView urlpatterns = [ - #path("", views.index, name="index"), + path("", TodoListView.as_view(), name="list"), + path("create", TodoCreateView.as_view(), name="create"), + path("edit//", TodoEditView.as_view(), name="edit"), + path("delete//", TodoDeleteView.as_view(), name="delete"), ] \ No newline at end of file diff --git a/backend/todolist/views.py b/backend/todolist/views.py index 91ea44a..a91ac1a 100644 --- a/backend/todolist/views.py +++ b/backend/todolist/views.py @@ -1,3 +1,53 @@ -from django.shortcuts import render +from django.views.generic.base import TemplateView +from django.views.generic.edit import DeleteView +from .forms import TodoForm, TodoEditForm +from .models import Todo +from django.shortcuts import redirect, render +from django.urls import reverse_lazy -# Create your views here. +class TodoListView(TemplateView): + template_name = "todolist/list.html" + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["todos"] = Todo.objects.all()[:5] + return context + +class TodoCreateView(TemplateView): + template_name = "todolist/create.html" + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["form"] = TodoForm() + return context + + def post(self, request): + form = TodoForm(request.POST) + if form.is_valid(): + form.save() + return redirect("list") + return render(request, "create.html", {"form": form}) + +class TodoEditView(TemplateView): + template_name = "todolist/edit.html" + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + id = kwargs["id"] + todo = Todo.objects.get(id=id) + context["form"] = TodoEditForm(instance=todo) + return context + + def post(self, request, id): + todo = Todo.objects.get(id=id) + form = TodoEditForm(request.POST, instance=todo) + if form.is_valid(): + form.save() + return redirect("list") + return render(request, "edit.html", {"form": form}) + +class TodoDeleteView(DeleteView): + model = Todo + success_url = reverse_lazy("list") + + \ No newline at end of file diff --git a/compose.yaml b/compose.yaml index e2db667..0e57679 100644 --- a/compose.yaml +++ b/compose.yaml @@ -22,5 +22,12 @@ services: volumes: - db-data:/var/lib/postgresql + adminer: + image: adminer + restart: always + ports: + - 8080:8080 + + volumes: db-data: \ No newline at end of file