From 1e3ab3bc7f8cb85c1b60e51377014d160d0e5049 Mon Sep 17 00:00:00 2001 From: Tomasz Herman Date: Fri, 24 Oct 2025 13:47:16 +0200 Subject: [PATCH 01/30] add .gitignore with .idea --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1da8522 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea From d6f0fc76484f3a6613925d0d76f6aa45ade0c64c Mon Sep 17 00:00:00 2001 From: Tomasz Herman Date: Fri, 24 Oct 2025 13:49:30 +0200 Subject: [PATCH 02/30] Initializa empty django project with todo_list --- manage.py | 22 ++++ todo_list/__init__.py | 0 .../__pycache__/__init__.cpython-313.pyc | Bin 0 -> 188 bytes .../__pycache__/settings.cpython-313.pyc | Bin 0 -> 2529 bytes todo_list/asgi.py | 16 +++ todo_list/settings.py | 122 ++++++++++++++++++ todo_list/urls.py | 22 ++++ todo_list/wsgi.py | 16 +++ 8 files changed, 198 insertions(+) create mode 100644 manage.py create mode 100644 todo_list/__init__.py create mode 100644 todo_list/__pycache__/__init__.cpython-313.pyc create mode 100644 todo_list/__pycache__/settings.cpython-313.pyc create mode 100644 todo_list/asgi.py create mode 100644 todo_list/settings.py create mode 100644 todo_list/urls.py create mode 100644 todo_list/wsgi.py diff --git a/manage.py b/manage.py new file mode 100644 index 0000000..f5f88b8 --- /dev/null +++ b/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'todo_list.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/todo_list/__init__.py b/todo_list/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/todo_list/__pycache__/__init__.cpython-313.pyc b/todo_list/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..531c9636916be840c21c3d936ea04f544e0efe5b GIT binary patch literal 188 zcmey&%ge<81PXD#GeGoX5CH>>P{wB#AY&>+I)f&o-%5reCLr%KNa|L!vsFxJacWU< zOh|riYIaOOWpYMhQEos{epYI7NpXxzR$^XyK9mcTEy>8wgYio8byMt2b@e#z4S?d&0xiRh0 zJJeY`;zwQ*Kt2-8QY4h6(9~0!gkko>96w6onG3XNe}$Xa*%gYX+Tj$CNvsU!t=WqO+Q_-3Rv#k@x)MZ^%6~kmYM1P4JCL0c~V+|9@#4@wB$6S+LtBfSK z6^$`WiI_vpYfRSw9A*f+!Y;FS!Fml)+d9FFqJe|9WGcGGz}IXk;8IcX7Z3psw@kBR z+|OoZy?q{y0N!k2X1lAZj2pPVeX=D(rsO1bMEvXss`C+b1*zp@a~xE-HBKvNZxoH z9IPR4O2aM0F~iACj8ZjjyfH}MnAMkOY(iBUJ1?ci4m1P%-5QbFxZH87-WaosA2%A? zC8}X%hd3r~cU0&#b_)QoCXaf7&AV+U48?|>bPM2(DMFVtAS|62X|Hu-66UlPOYke` z1k<`X)IBafCsSwWI~lZYPbeQ}=M009EbX%ct6c60U&`CQe4&c$AXlk~E)^(OghIK5 ztof5f>>5pll{y{BpL;lVK*rlrS2d5TRo*(ui}6ZTOnlo419M2HJ+_}OtrtqX?JIE` zJb|l{vK~)_?p8!cGK^iF$RgYeitM^$YX&Bq=`>>3#7Jo?s^k>QG|L$0kE*ai_gnYGQk=IT)1_wWcwXTcn*;Z zfShx@+sQn?#?^{~2*_n|t-u%azfvEZN5TFfcfan`j!_r%Hr}aM_8KjTv@3%L)Trm( z)*UWEYPNK3v@-RKtY@5etA5-F_0jXjcJ}Px12~ediXW0i@a6m)F+4E#y);c9dBU{s z?>UOTc;u&|iJyW$K71Eh*pDpy7PtJ+ zd$IT7K+@BTzfT6^9+0G{1k;Q5gH(#A4-(0P)ZAf|c~AK+$NOG?Dtr`*O!@oXSj^K4 z^*^IhOK+(JpiadPlI%fZ?w1GqiEBqw-UR4OxjOSyX!>p9dEe^+yP&(Mj4z&!FRFvZ v`Pe6(x71vJk(!z7#SWu0z0hG~x)(fzp#A+Q6`zGb!_ Date: Fri, 24 Oct 2025 13:56:44 +0200 Subject: [PATCH 03/30] Add Task and Tag models with ManyToMany relationship --- catalog/models.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 catalog/models.py diff --git a/catalog/models.py b/catalog/models.py new file mode 100644 index 0000000..84e3f9b --- /dev/null +++ b/catalog/models.py @@ -0,0 +1,19 @@ +from django.db import models + + +class Tag(models.Model): + name = models.CharField(max_length=30, unique=True) + + def __str__(self): + return self.name + + +class Task(models.Model): + content = models.TextField() + datetime = models.DateTimeField(auto_now_add=True) + deadline = models.DateTimeField(null=True, blank=True) + is_done = models.BooleanField(default=False) + tags = models.ManyToManyField(Tag, related_name="tasks") + + def __str__(self): + return self.content From 13e097ef280872a038a0d1ce0919bd3c520d02c0 Mon Sep 17 00:00:00 2001 From: Tomasz Herman Date: Fri, 24 Oct 2025 13:57:05 +0200 Subject: [PATCH 04/30] Register Task and Tag models in admin panel --- catalog/admin.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 catalog/admin.py diff --git a/catalog/admin.py b/catalog/admin.py new file mode 100644 index 0000000..761cbf0 --- /dev/null +++ b/catalog/admin.py @@ -0,0 +1,15 @@ +from django.contrib import admin +from .models import Task, Tag + + +@admin.register(Task) +class TaskAdmin(admin.ModelAdmin): + list_display = ["content", "datetime", "deadline", "is_done"] + list_filter = ["is_done", "tags"] + search_fields = ["content"] + + +@admin.register(Tag) +class TagAdmin(admin.ModelAdmin): + list_display = ["name"] + search_fields = ["name"] From c866b3daad45aef16a7cfdce7339828e08df0649 Mon Sep 17 00:00:00 2001 From: Tomasz Herman Date: Fri, 24 Oct 2025 13:57:43 +0200 Subject: [PATCH 05/30] Create forms for Task and Tag models --- catalog/forms.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 catalog/forms.py diff --git a/catalog/forms.py b/catalog/forms.py new file mode 100644 index 0000000..ee2bb92 --- /dev/null +++ b/catalog/forms.py @@ -0,0 +1,14 @@ +from django import forms +from .models import Task, Tag + + +class TaskForm(forms.ModelForm): + class Meta: + model = Task + fields = ["content", "deadline", "tags"] + + +class TagForm(forms.ModelForm): + class Meta: + model = Tag + fields = ["name"] From 46ed00ba2f152480006ec979012da76607d42b17 Mon Sep 17 00:00:00 2001 From: Tomasz Herman Date: Fri, 24 Oct 2025 13:58:22 +0200 Subject: [PATCH 06/30] Implement CRUD views for Tasks and Tags --- catalog/views.py | 88 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 catalog/views.py diff --git a/catalog/views.py b/catalog/views.py new file mode 100644 index 0000000..e296d76 --- /dev/null +++ b/catalog/views.py @@ -0,0 +1,88 @@ +from django.shortcuts import render, get_object_or_404, redirect +from .models import Task, Tag +from .forms import TaskForm, TagForm + + +def task_list(request): + tasks = ( + Task.objects.all() + .order_by("is_done", "-datetime") + .prefetch_related("tags") + ) + return render(request, "task_list.html", {"tasks": tasks}) + + +def add_task(request): + if request.method == "POST": + form = TaskForm(request.POST) + if form.is_valid(): + task = form.save(commit=False) + task.save() + form.save_m2m() + return redirect("task_list") + else: + form = TaskForm() + return render(request, "task_form.html", {"form": form}) + + +def update_task(request, pk): + task = get_object_or_404(Task, pk=pk) + if request.method == "POST": + form = TaskForm(request.POST, instance=task) + if form.is_valid(): + form.save() + return redirect("task_list") + else: + form = TaskForm(instance=task) + return render(request, "task_form.html", {"form": form}) + + +def delete_task(request, pk): + task = get_object_or_404(Task, pk=pk) + if request.method == "POST": + task.delete() + return redirect("task_list") + return render(request, "task_confirm_delete.html", {"task": task}) + + +def toggle_task_status(request, pk): + task = get_object_or_404(Task, pk=pk) + task.is_done = not task.is_done + task.save() + return redirect("task_list") + + +def tag_list(request): + tags = Tag.objects.all().order_by("name") + return render(request, "tag_list.html", {"tags": tags}) + + +def add_tag(request): + if request.method == "POST": + form = TagForm(request.POST) + if form.is_valid(): + form.save() + return redirect("tag_list") + else: + form = TagForm() + return render(request, "tag_form.html", {"form": form}) + + +def update_tag(request, pk): + tag = get_object_or_404(Tag, pk=pk) + if request.method == "POST": + form = TagForm(request.POST, instance=tag) + if form.is_valid(): + form.save() + return redirect("tag_list") + else: + form = TagForm(instance=tag) + return render(request, "tag_form.html", {"form": form}) + + +def delete_tag(request, pk): + tag = get_object_or_404(Tag, pk=pk) + if request.method == "POST": + tag.delete() + return redirect("tag_list") + return render(request, "tag_confirm_delete.html", {"tag": tag}) From 54311208eb5ac8794afeea3601283dfe01cc4cea Mon Sep 17 00:00:00 2001 From: Tomasz Herman Date: Fri, 24 Oct 2025 13:59:39 +0200 Subject: [PATCH 07/30] Configure URL routing for catalog app --- catalog/urls.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 catalog/urls.py diff --git a/catalog/urls.py b/catalog/urls.py new file mode 100644 index 0000000..c07a7b6 --- /dev/null +++ b/catalog/urls.py @@ -0,0 +1,18 @@ +from django.urls import path +from . import views + +urlpatterns = [ + path("", views.task_list, name="task_list"), + path("tasks/add/", views.add_task, name="add_task"), + path("tasks/update//", views.update_task, name="update_task"), + path("tasks/delete//", views.delete_task, name="delete_task"), + path( + "tasks/toggle//", + views.toggle_task_status, + name="toggle_task_status" + ), + path("tags/", views.tag_list, name="tag_list"), + path("tags/add/", views.add_tag, name="add_tag"), + path("tags/update//", views.update_tag, name="update_tag"), + path("tags/delete//", views.delete_tag, name="delete_tag"), +] From e81b7b1c04af040a5058fdf34a34b7901f946157 Mon Sep 17 00:00:00 2001 From: Tomasz Herman Date: Fri, 24 Oct 2025 13:59:58 +0200 Subject: [PATCH 08/30] Include catalog URLs in main project --- todo_list/urls.py | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/todo_list/urls.py b/todo_list/urls.py index 0d879e4..a9ce173 100644 --- a/todo_list/urls.py +++ b/todo_list/urls.py @@ -1,22 +1,7 @@ -""" -URL configuration for todo_list project. - -The `urlpatterns` list routes URLs to views. For more information please see: - https://docs.djangoproject.com/en/5.2/topics/http/urls/ -Examples: -Function views - 1. Add an import: from my_app import views - 2. Add a URL to urlpatterns: path('', views.home, name='home') -Class-based views - 1. Add an import: from other_app.views import Home - 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') -Including another URLconf - 1. Import the include() function: from django.urls import include, path - 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) -""" from django.contrib import admin -from django.urls import path +from django.urls import path, include urlpatterns = [ - path('admin/', admin.site.urls), + path("admin/", admin.site.urls), + path("", include("catalog.urls")), ] From 1ce25dc6e69f6100194d1a32689373a5cc7b2e3c Mon Sep 17 00:00:00 2001 From: Tomasz Herman Date: Fri, 24 Oct 2025 14:00:43 +0200 Subject: [PATCH 09/30] Add catalog app to INSTALLED_APPS --- todo_list/settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/todo_list/settings.py b/todo_list/settings.py index eb76164..c228061 100644 --- a/todo_list/settings.py +++ b/todo_list/settings.py @@ -37,6 +37,7 @@ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'catalog', ] MIDDLEWARE = [ From 657d704e309a59e81296cfc627d632a17dfff892 Mon Sep 17 00:00:00 2001 From: Tomasz Herman Date: Fri, 24 Oct 2025 14:01:28 +0200 Subject: [PATCH 10/30] Create sidebar template with navigation links --- catalog/templates/sidebar.html | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 catalog/templates/sidebar.html diff --git a/catalog/templates/sidebar.html b/catalog/templates/sidebar.html new file mode 100644 index 0000000..a4dba21 --- /dev/null +++ b/catalog/templates/sidebar.html @@ -0,0 +1,5 @@ + +
From 88d9e0aa7be3d130e5cbb6b5319e5ec68834c5d9 Mon Sep 17 00:00:00 2001 From: Tomasz Herman Date: Fri, 24 Oct 2025 14:01:50 +0200 Subject: [PATCH 11/30] Create task list template with CRUD actions --- catalog/templates/task_list.html | 45 ++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 catalog/templates/task_list.html diff --git a/catalog/templates/task_list.html b/catalog/templates/task_list.html new file mode 100644 index 0000000..abee6b6 --- /dev/null +++ b/catalog/templates/task_list.html @@ -0,0 +1,45 @@ + + + + + + TODO List + + + {% include "sidebar.html" %} + +

TODO list

+ Add task + +
    + {% for task in tasks %} +
  • + {{ task.content }} + {% if not task.is_done %} + Not done +
    + {% csrf_token %} + +
    + {% else %} + Done +
    + {% csrf_token %} + +
    + {% endif %} +
    + Created: {{ task.datetime }} + {% if task.deadline %} +
    Deadline: {{ task.deadline }} + {% endif %} +
    + Tags: {% for tag in task.tags.all %}{{ tag.name }}{% if not forloop.last %}, {% endif %}{% endfor %} +
    + Update | + Delete +
  • + {% endfor %} +
+ + From a78950e0a865f26186f90947deb18940647dd80d Mon Sep 17 00:00:00 2001 From: Tomasz Herman Date: Fri, 24 Oct 2025 14:02:14 +0200 Subject: [PATCH 12/30] Create tag list template with table view --- catalog/templates/tag_list.html | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 catalog/templates/tag_list.html diff --git a/catalog/templates/tag_list.html b/catalog/templates/tag_list.html new file mode 100644 index 0000000..d279368 --- /dev/null +++ b/catalog/templates/tag_list.html @@ -0,0 +1,33 @@ + + + + + + Tags + + + {% include "sidebar.html" %} + +

Tags

+ Add + + + + + + + + + + + {% for tag in tags %} + + + + + + {% endfor %} + +
NameUpdateDelete
{{ tag.name }}UpdateDelete
+ + From 12e7eb14521b836f05d19368c12360c02e53eab3 Mon Sep 17 00:00:00 2001 From: Tomasz Herman Date: Fri, 24 Oct 2025 14:02:36 +0200 Subject: [PATCH 13/30] Create task form template for add and update --- catalog/templates/task_form.html | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 catalog/templates/task_form.html diff --git a/catalog/templates/task_form.html b/catalog/templates/task_form.html new file mode 100644 index 0000000..8852c0f --- /dev/null +++ b/catalog/templates/task_form.html @@ -0,0 +1,19 @@ + + + + + + Task Form + + + {% include "sidebar.html" %} + +

Add / Edit Task

+
+ {% csrf_token %} + {{ form.as_p }} + + Cancel +
+ + From 33c389af1b3182ea608b60e8f2adfff712d4b926 Mon Sep 17 00:00:00 2001 From: Tomasz Herman Date: Fri, 24 Oct 2025 14:03:15 +0200 Subject: [PATCH 14/30] Create tag form template for add and update --- catalog/templates/tag_form.html | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 catalog/templates/tag_form.html diff --git a/catalog/templates/tag_form.html b/catalog/templates/tag_form.html new file mode 100644 index 0000000..342aea1 --- /dev/null +++ b/catalog/templates/tag_form.html @@ -0,0 +1,19 @@ + + + + + + Tag Form + + + {% include "sidebar.html" %} + +

Add / Edit Tag

+
+ {% csrf_token %} + {{ form.as_p }} + + Cancel +
+ + From a356565b1ebddada3974cb7a79f4c0f66deba992 Mon Sep 17 00:00:00 2001 From: Tomasz Herman Date: Fri, 24 Oct 2025 14:03:36 +0200 Subject: [PATCH 15/30] Create task delete confirmation template --- catalog/templates/task_confirm_delete.html | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 catalog/templates/task_confirm_delete.html diff --git a/catalog/templates/task_confirm_delete.html b/catalog/templates/task_confirm_delete.html new file mode 100644 index 0000000..a178923 --- /dev/null +++ b/catalog/templates/task_confirm_delete.html @@ -0,0 +1,19 @@ + + + + + + Delete Task + + + {% include "sidebar.html" %} + +

Are you sure you want to delete this task?

+

{{ task.content }}

+
+ {% csrf_token %} + + Cancel +
+ + From 3badcebd9146b280456e2c4b79c14d774f80e9fa Mon Sep 17 00:00:00 2001 From: Tomasz Herman Date: Fri, 24 Oct 2025 14:04:01 +0200 Subject: [PATCH 16/30] Create tag delete confirmation template --- catalog/templates/tag_confirm_delete.html | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 catalog/templates/tag_confirm_delete.html diff --git a/catalog/templates/tag_confirm_delete.html b/catalog/templates/tag_confirm_delete.html new file mode 100644 index 0000000..adb0d1f --- /dev/null +++ b/catalog/templates/tag_confirm_delete.html @@ -0,0 +1,19 @@ + + + + + + Delete Tag + + + {% include "sidebar.html" %} + +

Are you sure you want to delete this tag?

+

{{ tag.name }}

+
+ {% csrf_token %} + + Cancel +
+ + From 59cc0bd19e8bf8812de37ac81cb403d53dde9ba9 Mon Sep 17 00:00:00 2001 From: Tomasz Herman Date: Fri, 24 Oct 2025 14:09:43 +0200 Subject: [PATCH 17/30] Configure static files settings --- catalog/migrations/0001_initial.py | 32 ++++++++++++++++++ catalog/migrations/__init__.py | 0 .../__pycache__/0001_initial.cpython-313.pyc | Bin 0 -> 1522 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 0 -> 197 bytes catalog/static/catalog/css/styles.css | 0 todo_list/settings.py | 11 ++++-- 6 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 catalog/migrations/0001_initial.py create mode 100644 catalog/migrations/__init__.py create mode 100644 catalog/migrations/__pycache__/0001_initial.cpython-313.pyc create mode 100644 catalog/migrations/__pycache__/__init__.cpython-313.pyc create mode 100644 catalog/static/catalog/css/styles.css diff --git a/catalog/migrations/0001_initial.py b/catalog/migrations/0001_initial.py new file mode 100644 index 0000000..c204240 --- /dev/null +++ b/catalog/migrations/0001_initial.py @@ -0,0 +1,32 @@ +# Generated by Django 5.2.7 on 2025-10-24 12:04 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Tag', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=30, unique=True)), + ], + ), + migrations.CreateModel( + name='Task', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('content', models.TextField()), + ('datetime', models.DateTimeField(auto_now_add=True)), + ('deadline', models.DateTimeField(blank=True, null=True)), + ('is_done', models.BooleanField(default=False)), + ('tags', models.ManyToManyField(related_name='tasks', to='catalog.tag')), + ], + ), + ] diff --git a/catalog/migrations/__init__.py b/catalog/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/catalog/migrations/__pycache__/0001_initial.cpython-313.pyc b/catalog/migrations/__pycache__/0001_initial.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c43b821390c14a6ad427079108943b82da532e79 GIT binary patch literal 1522 zcma)6y>Ht_6hBfV^AP(ZHj`x;VhmdMil8B zPid4XK#R^<3iw~>*3o0ejFLLYxG6vQtzkBx{uV!ac z2%e8y|1=L3g#HMW$)k>it8EZ|K?X9Uuh724qH-C%^(@RAWyi|ZPg0Q7L`*UelMRW*44Ela#8gu| z%G`8`WFQkW6fck3sZ4Pz@@h2O}Q!?Gh6b1=1TwXT(gjC zX5W3AD3S-0JG%_-xh7&Y(h#z3?Fsq8ZbcDk(%~MiGfFtM#LOwP+k|y-i*`lQ zr_3gf{hW&QQ_7A#pJJD^sZfITas}drT|u5CV=zB2cIMTeD~NZ`#VGdp474uWA|FoZ~?@7ayd zp`?4k(M58nN!VDd(PumoXLo^H4GIvc>3g2%P~t{f_JFwEnis5*A?2OY$=EGo>~k2w zIwqVm`?$lYk1_iIGGD=qM04j8^BcG~->i9U+A<$@>%gG>ka>@3o%`nQW8yZvu?oAq z>A4e)dv`4Fj$`}W99Pr4o_KS8eSHIuOR;v^WkEZIOCb1fVfh)o$;`d@Vx&k5+KaD8 z36z{4CRPTCm5bcco802dr^EcMLH^dc@_M!RJ?^=zpZ9w@zsTj!mWGAOpiuek=#|nh z-0$goBQ>^=d8=y4)F^W!PX3*7if4Pn((OU%_V1;&o?gAky?6HQu)HxSZ=CafdAFzE zziColZT8Dw_VfoAxzMpXC{@qZerda>e>Ub+9TckPk6xGig-1R8yU}bs;FJPRx%oNm z$9=Xjslg#kQql@*yJj7Sy%DxURHfj0BJ4*XiNvQ->us}5P~l&R{9v$0F-emC){s>B VQ!7f^%hXU`?dz+5Ay7i^e*s*!j(-3E literal 0 HcmV?d00001 diff --git a/catalog/migrations/__pycache__/__init__.cpython-313.pyc b/catalog/migrations/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8a0c8c2d76069a04a810796da768eaceac39496a GIT binary patch literal 197 zcmey&%ge<81pFDlGeGoX5CH>>P{wB#AY&>+I)f&o-%5reCLr%KNa|LKvsFxJacWU< zOh|riYIaOOWpYMhQEos{epYI7NpXxzR$^XyK9mcTEy>8wgYio8byMpF literal 0 HcmV?d00001 diff --git a/catalog/static/catalog/css/styles.css b/catalog/static/catalog/css/styles.css new file mode 100644 index 0000000..e69de29 diff --git a/todo_list/settings.py b/todo_list/settings.py index c228061..2f09f7e 100644 --- a/todo_list/settings.py +++ b/todo_list/settings.py @@ -59,6 +59,7 @@ 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ + 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', @@ -95,7 +96,7 @@ 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', }, { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + 'NAME': 'django.contrib.auth.password_validation.NumimumPasswordValidator', }, ] @@ -115,7 +116,13 @@ # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/5.2/howto/static-files/ -STATIC_URL = 'static/' +STATIC_URL = '/static/' + +STATICFILES_DIRS = [ + BASE_DIR / "catalog" / "static", +] + +STATIC_ROOT = BASE_DIR / "staticfiles" # Default primary key field type # https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field From be0f3902bc4fc347326b9476c33b45f42380191d Mon Sep 17 00:00:00 2001 From: Tomasz Herman Date: Fri, 24 Oct 2025 14:10:57 +0200 Subject: [PATCH 18/30] Add CSS stylesheet for application styling --- catalog/static/catalog/css/styles.css | 253 ++++++++++++++++++++++++++ 1 file changed, 253 insertions(+) diff --git a/catalog/static/catalog/css/styles.css b/catalog/static/catalog/css/styles.css index e69de29..8dbeb67 100644 --- a/catalog/static/catalog/css/styles.css +++ b/catalog/static/catalog/css/styles.css @@ -0,0 +1,253 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: Arial, sans-serif; + display: flex; + min-height: 100vh; +} + +/* Sidebar */ +.sidebar { + width: 250px; + background-color: #f8f9fa; + padding: 20px; + border-right: 1px solid #ddd; +} + +.sidebar h2 { + margin-bottom: 20px; + font-size: 24px; +} + +.sidebar nav { + display: flex; + flex-direction: column; + gap: 10px; +} + +.sidebar a { + padding: 10px 15px; + text-decoration: none; + color: #007bff; + background-color: white; + border: 1px solid #007bff; + border-radius: 4px; + text-align: center; + transition: all 0.3s; +} + +.sidebar a:hover { + background-color: #007bff; + color: white; +} + +/* Main content */ +.main-content { + flex: 1; + padding: 40px; +} + +.header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 30px; +} + +.header h1 { + font-size: 48px; + font-weight: normal; +} + +.btn-add { + background-color: #007bff; + color: white; + padding: 12px 24px; + text-decoration: none; + border-radius: 4px; + border: none; + font-size: 16px; + cursor: pointer; +} + +.btn-add:hover { + background-color: #0056b3; +} + +/* Task list */ +.task-list { + list-style: none; +} + +.task-item { + background-color: white; + border: 1px solid #ddd; + padding: 20px; + margin-bottom: 15px; + border-radius: 4px; +} + +.task-header { + display: flex; + justify-content: space-between; + align-items: start; + margin-bottom: 10px; +} + +.task-title { + font-size: 20px; + font-weight: bold; + flex: 1; +} + +.task-status { + font-weight: bold; + margin-left: 15px; +} + +.status-done { + color: #28a745; +} + +.status-not-done { + color: #dc3545; +} + +.task-details { + color: #666; + font-size: 14px; + margin-bottom: 10px; +} + +.task-tags { + color: #666; + font-size: 14px; + margin-bottom: 15px; +} + +.task-actions { + display: flex; + gap: 10px; + align-items: center; +} + +.btn-action { + padding: 8px 16px; + text-decoration: none; + border-radius: 4px; + border: none; + cursor: pointer; + font-size: 14px; +} + +.btn-update { + background-color: white; + color: #007bff; + border: 1px solid #007bff; +} + +.btn-update:hover { + background-color: #007bff; + color: white; +} + +.btn-delete { + background-color: white; + color: #dc3545; + border: 1px solid #dc3545; +} + +.btn-delete:hover { + background-color: #dc3545; + color: white; +} + +.btn-complete { + background-color: #28a745; + color: white; + padding: 8px 16px; +} + +.btn-complete:hover { + background-color: #218838; +} + +.btn-undo { + background-color: #6c757d; + color: white; + padding: 8px 16px; +} + +.btn-undo:hover { + background-color: #5a6268; +} + +/* Table for tags */ +table { + width: 100%; + border-collapse: collapse; + background-color: white; +} + +table th, +table td { + padding: 12px; + text-align: left; + border: 1px solid #ddd; +} + +table th { + background-color: #f8f9fa; + font-weight: bold; +} + +/* Forms */ +form { + background-color: white; + padding: 20px; + border: 1px solid #ddd; + border-radius: 4px; + max-width: 600px; +} + +form p { + margin-bottom: 15px; +} + +form label { + display: block; + margin-bottom: 5px; + font-weight: bold; +} + +form input[type="text"], +form input[type="datetime-local"], +form textarea, +form select { + width: 100%; + padding: 8px; + border: 1px solid #ddd; + border-radius: 4px; +} + +form textarea { + min-height: 100px; +} + +form button[type="submit"] { + background-color: #28a745; + color: white; + padding: 10px 20px; + border: none; + border-radius: 4px; + cursor: pointer; + margin-right: 10px; +} + +form button[type="submit"]:hover { + background-color: #218838; +} From 64993a658c0f1689e412c7195c5f0613f68275f0 Mon Sep 17 00:00:00 2001 From: Tomasz Herman Date: Fri, 24 Oct 2025 14:11:06 +0200 Subject: [PATCH 19/30] Update task list template with improved UI layout --- catalog/templates/task_list.html | 97 +++++++++++++++++++++----------- 1 file changed, 64 insertions(+), 33 deletions(-) diff --git a/catalog/templates/task_list.html b/catalog/templates/task_list.html index abee6b6..0fc12aa 100644 --- a/catalog/templates/task_list.html +++ b/catalog/templates/task_list.html @@ -1,45 +1,76 @@ +{% load static %} TODO List + - {% include "sidebar.html" %} + -

TODO list

- Add task +
+
+

TODO list

+ Add task +
-
    - {% for task in tasks %} -
  • - {{ task.content }} - {% if not task.is_done %} - Not done -
    - {% csrf_token %} - -
    - {% else %} - Done -
    - {% csrf_token %} - -
    - {% endif %} -
    - Created: {{ task.datetime }} - {% if task.deadline %} -
    Deadline: {{ task.deadline }} - {% endif %} -
    - Tags: {% for tag in task.tags.all %}{{ tag.name }}{% if not forloop.last %}, {% endif %}{% endfor %} -
    - Update | - Delete -
  • - {% endfor %} -
+
    + {% for task in tasks %} +
  • +
    +
    {{ task.content }}
    + {% if not task.is_done %} + Not done + {% else %} + Done + {% endif %} +
    + +
    + Created: {{ task.datetime|date:"F d, Y, g:i a" }} + {% if task.deadline %} + Deadline: {{ task.deadline|date:"F d, Y, g:i a" }} + {% endif %} +
    + +
    + Tags: + {% for tag in task.tags.all %} + {{ tag.name }}{% if not forloop.last %}, {% endif %} + {% empty %} + No tags + {% endfor %} +
    + +
    + Update + Delete + + {% if not task.is_done %} +
    + {% csrf_token %} + +
    + {% else %} +
    + {% csrf_token %} + +
    + {% endif %} +
    +
  • + {% empty %} +
  • No tasks yet. Click "Add task" to create one!
  • + {% endfor %} +
+
From f11cca61af7aaf7e1b58c5dfe6d64d958b513c21 Mon Sep 17 00:00:00 2001 From: Tomasz Herman Date: Fri, 24 Oct 2025 14:12:25 +0200 Subject: [PATCH 20/30] Add .gitignore for Python and Django files --- .gitignore | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 1da8522..84fc93f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,35 @@ -.idea +# Utwórz plik .gitignore w głównym katalogu projektu +cat > .gitignore << 'EOF' +# Python +*.py[cod] +*$py.class +*.so +__pycache__/ +*.egg-info/ +dist/ +build/ + +# Django +*.log +db.sqlite3 +db.sqlite3-journal +/media +/staticfiles + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# Environment +.env +venv/ +env/ +ENV/ + +# OS +.DS_Store +Thumbs.db +EOF From 0ba64dba0abfd2cde6329eee310703696ab75060 Mon Sep 17 00:00:00 2001 From: Tomasz Herman Date: Fri, 24 Oct 2025 14:12:41 +0200 Subject: [PATCH 21/30] Add catalog app configuration files --- catalog/__init__.py | 0 catalog/apps.py | 6 ++++++ catalog/tests.py | 3 +++ 3 files changed, 9 insertions(+) create mode 100644 catalog/__init__.py create mode 100644 catalog/apps.py create mode 100644 catalog/tests.py diff --git a/catalog/__init__.py b/catalog/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/catalog/apps.py b/catalog/apps.py new file mode 100644 index 0000000..20d273c --- /dev/null +++ b/catalog/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class CatalogConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'catalog' diff --git a/catalog/tests.py b/catalog/tests.py new file mode 100644 index 0000000..de8bdc0 --- /dev/null +++ b/catalog/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. From 36a602f5546dbf059681a3453011ef1d18379096 Mon Sep 17 00:00:00 2001 From: Tomasz Herman Date: Fri, 24 Oct 2025 14:34:12 +0200 Subject: [PATCH 22/30] Add inline CSS styling to tag list template --- catalog/templates/tag_list.html | 196 ++++++++++++++++++++++++++++---- 1 file changed, 173 insertions(+), 23 deletions(-) diff --git a/catalog/templates/tag_list.html b/catalog/templates/tag_list.html index d279368..3c24703 100644 --- a/catalog/templates/tag_list.html +++ b/catalog/templates/tag_list.html @@ -4,30 +4,180 @@ Tags + - {% include "sidebar.html" %} - -

Tags

- Add - - - - - - - - - - - {% for tag in tags %} - - - - - - {% endfor %} - -
NameUpdateDelete
{{ tag.name }}UpdateDelete
+ + +
+
+

Tags

+ Add +
+ + + + + + + + + + + {% for tag in tags %} + + + + + + {% empty %} + + + + {% endfor %} + +
NameUpdateDelete
{{ tag.name }} + Update + + Delete +
No tags yet. Click "Add" to create one!
+
From 3388ee14b7d40eddb1bb270002efa2dcc8b5fa85 Mon Sep 17 00:00:00 2001 From: Tomasz Herman Date: Fri, 24 Oct 2025 14:34:53 +0200 Subject: [PATCH 23/30] Update CSS stylesheet with comprehensive styling rules --- catalog/static/catalog/css/styles.css | 137 ++++++++++++++++++++++---- 1 file changed, 120 insertions(+), 17 deletions(-) diff --git a/catalog/static/catalog/css/styles.css b/catalog/static/catalog/css/styles.css index 8dbeb67..60befa3 100644 --- a/catalog/static/catalog/css/styles.css +++ b/catalog/static/catalog/css/styles.css @@ -8,19 +8,22 @@ body { font-family: Arial, sans-serif; display: flex; min-height: 100vh; + background-color: #f5f5f5; } /* Sidebar */ .sidebar { width: 250px; - background-color: #f8f9fa; + background-color: #ffffff; padding: 20px; - border-right: 1px solid #ddd; + border-right: 1px solid #e0e0e0; + box-shadow: 2px 0 5px rgba(0, 0, 0, 0.05); } .sidebar h2 { margin-bottom: 20px; font-size: 24px; + color: #333; } .sidebar nav { @@ -30,14 +33,15 @@ body { } .sidebar a { - padding: 10px 15px; + padding: 12px 15px; text-decoration: none; color: #007bff; - background-color: white; + background-color: #f8f9fa; border: 1px solid #007bff; border-radius: 4px; text-align: center; transition: all 0.3s; + font-size: 16px; } .sidebar a:hover { @@ -49,6 +53,7 @@ body { .main-content { flex: 1; padding: 40px; + background-color: #f5f5f5; } .header { @@ -61,17 +66,19 @@ body { .header h1 { font-size: 48px; font-weight: normal; + color: #333; } .btn-add { background-color: #007bff; color: white; - padding: 12px 24px; + padding: 12px 30px; text-decoration: none; border-radius: 4px; border: none; font-size: 16px; cursor: pointer; + transition: background-color 0.3s; } .btn-add:hover { @@ -85,10 +92,11 @@ body { .task-item { background-color: white; - border: 1px solid #ddd; + border: 1px solid #e0e0e0; padding: 20px; margin-bottom: 15px; - border-radius: 4px; + border-radius: 8px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); } .task-header { @@ -102,11 +110,13 @@ body { font-size: 20px; font-weight: bold; flex: 1; + color: #333; } .task-status { font-weight: bold; margin-left: 15px; + font-size: 16px; } .status-done { @@ -133,6 +143,7 @@ body { display: flex; gap: 10px; align-items: center; + flex-wrap: wrap; } .btn-action { @@ -142,6 +153,7 @@ body { border: none; cursor: pointer; font-size: 14px; + transition: all 0.3s; } .btn-update { @@ -170,6 +182,7 @@ body { background-color: #28a745; color: white; padding: 8px 16px; + border: none; } .btn-complete:hover { @@ -180,6 +193,7 @@ body { background-color: #6c757d; color: white; padding: 8px 16px; + border: none; } .btn-undo:hover { @@ -191,37 +205,67 @@ table { width: 100%; border-collapse: collapse; background-color: white; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); + border-radius: 8px; + overflow: hidden; } table th, table td { - padding: 12px; + padding: 15px; text-align: left; - border: 1px solid #ddd; + border-bottom: 1px solid #e0e0e0; } table th { background-color: #f8f9fa; font-weight: bold; + font-size: 16px; + color: #333; +} + +table tbody tr:last-child td { + border-bottom: none; +} + +table tbody tr:hover { + background-color: #f8f9fa; +} + +.btn-table-action { + background-color: #6c757d; + color: white; + padding: 8px 20px; + text-decoration: none; + border-radius: 4px; + font-size: 14px; + display: inline-block; + transition: background-color 0.3s; +} + +.btn-table-action:hover { + background-color: #5a6268; } /* Forms */ -form { +.form-container { background-color: white; - padding: 20px; - border: 1px solid #ddd; - border-radius: 4px; + padding: 30px; + border: 1px solid #e0e0e0; + border-radius: 8px; max-width: 600px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); } form p { - margin-bottom: 15px; + margin-bottom: 20px; } form label { display: block; - margin-bottom: 5px; + margin-bottom: 8px; font-weight: bold; + color: #333; } form input[type="text"], @@ -229,25 +273,84 @@ form input[type="datetime-local"], form textarea, form select { width: 100%; - padding: 8px; + padding: 10px; border: 1px solid #ddd; border-radius: 4px; + font-size: 14px; } form textarea { min-height: 100px; + resize: vertical; +} + +form select[multiple] { + height: 120px; } form button[type="submit"] { background-color: #28a745; color: white; - padding: 10px 20px; + padding: 12px 24px; border: none; border-radius: 4px; cursor: pointer; margin-right: 10px; + font-size: 16px; + transition: background-color 0.3s; } form button[type="submit"]:hover { background-color: #218838; } + +.btn-cancel { + background-color: #6c757d; + color: white; + padding: 12px 24px; + text-decoration: none; + border-radius: 4px; + font-size: 16px; + display: inline-block; + transition: background-color 0.3s; +} + +.btn-cancel:hover { + background-color: #5a6268; +} + +/* Confirmation pages */ +.confirm-container { + background-color: white; + padding: 30px; + border: 1px solid #e0e0e0; + border-radius: 8px; + max-width: 600px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); +} + +.confirm-container h2 { + color: #dc3545; + margin-bottom: 20px; +} + +.confirm-container p { + margin-bottom: 20px; + font-size: 16px; +} + +.btn-confirm-delete { + background-color: #dc3545; + color: white; + padding: 12px 24px; + border: none; + border-radius: 4px; + cursor: pointer; + margin-right: 10px; + font-size: 16px; + transition: background-color 0.3s; +} + +.btn-confirm-delete:hover { + background-color: #c82333; +} From 9148c6c551533048d4f7e04d7fd07c9169f32aa7 Mon Sep 17 00:00:00 2001 From: Tomasz Herman Date: Fri, 24 Oct 2025 14:35:01 +0200 Subject: [PATCH 24/30] Add styled tag deletion confirmation template --- catalog/templates/tag_confirm_delete.html | 30 ++++++++++++++++------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/catalog/templates/tag_confirm_delete.html b/catalog/templates/tag_confirm_delete.html index adb0d1f..c5d0fe2 100644 --- a/catalog/templates/tag_confirm_delete.html +++ b/catalog/templates/tag_confirm_delete.html @@ -1,19 +1,31 @@ +{% load static %} - Delete Tag + Delete Task + - {% include "sidebar.html" %} + -

Are you sure you want to delete this tag?

-

{{ tag.name }}

-
- {% csrf_token %} - - Cancel -
+
+
+

Are you sure you want to delete this task?

+

{{ task.content }}

+
+ {% csrf_token %} + + Cancel +
+
+
From 89ca26ef915202d3f362a242ca86406822374936 Mon Sep 17 00:00:00 2001 From: Tomasz Herman Date: Fri, 24 Oct 2025 14:35:23 +0200 Subject: [PATCH 25/30] Add styled tag form template for create and update --- catalog/templates/tag_form.html | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/catalog/templates/tag_form.html b/catalog/templates/tag_form.html index 342aea1..dfbfd86 100644 --- a/catalog/templates/tag_form.html +++ b/catalog/templates/tag_form.html @@ -1,19 +1,32 @@ +{% load static %} Tag Form + - {% include "sidebar.html" %} + -

Add / Edit Tag

-
- {% csrf_token %} - {{ form.as_p }} - - Cancel -
+
+

{% if form.instance.pk %}Edit Tag{% else %}Add Tag{% endif %}

+ +
+
+ {% csrf_token %} + {{ form.as_p }} + + Cancel +
+
+
From 3d79a91f4ba320f367367c1c43b8ee720f0d95d6 Mon Sep 17 00:00:00 2001 From: Tomasz Herman Date: Fri, 24 Oct 2025 14:35:34 +0200 Subject: [PATCH 26/30] Add styled task form template for create and update --- catalog/templates/task_form.html | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/catalog/templates/task_form.html b/catalog/templates/task_form.html index 8852c0f..d791915 100644 --- a/catalog/templates/task_form.html +++ b/catalog/templates/task_form.html @@ -1,19 +1,32 @@ +{% load static %} Task Form + - {% include "sidebar.html" %} + -

Add / Edit Task

-
- {% csrf_token %} - {{ form.as_p }} - - Cancel -
+
+

{% if form.instance.pk %}Edit Task{% else %}Add Task{% endif %}

+ +
+
+ {% csrf_token %} + {{ form.as_p }} + + Cancel +
+
+
From d2b506394827731fe6042c3853461817786c9fc4 Mon Sep 17 00:00:00 2001 From: Tomasz Herman Date: Fri, 24 Oct 2025 14:35:42 +0200 Subject: [PATCH 27/30] Update task list template with inline CSS styling --- catalog/templates/task_list.html | 80 +++++++++++--------------------- 1 file changed, 28 insertions(+), 52 deletions(-) diff --git a/catalog/templates/task_list.html b/catalog/templates/task_list.html index 0fc12aa..a21ee48 100644 --- a/catalog/templates/task_list.html +++ b/catalog/templates/task_list.html @@ -1,11 +1,10 @@ -{% load static %} - TODO List - + Tags +