From 0afc5ee8d7a660c9eefca58053cef1350f6b4015 Mon Sep 17 00:00:00 2001 From: Disco DeDisco Date: Sat, 24 Jan 2026 13:00:12 -0500 Subject: [PATCH] defined Meta ordering of the Item() model in apps.dashboard.models; Item() also now returns a __str__ result; in .forms, defined a specific use-case of is_valid() method; a pair of new UTs in .tests.test_models help confirm str representation and list order of items; .test_forms now ensures the .is-invalid bootstrap class is tested as a css class attr; migrations run; full UT & FT suite back to passing state (tho a refactor of flimsy form customizations is desperately needed) --- src/apps/dashboard/forms.py | 6 ++++++ .../migrations/0005_alter_item_options.py | 17 +++++++++++++++++ src/apps/dashboard/models.py | 6 +++++- src/apps/dashboard/tests/test_forms.py | 9 +++++++++ src/apps/dashboard/tests/test_models.py | 14 ++++++++++++++ src/apps/dashboard/views.py | 7 +++---- 6 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 src/apps/dashboard/migrations/0005_alter_item_options.py diff --git a/src/apps/dashboard/forms.py b/src/apps/dashboard/forms.py index 1b32561..955a7f9 100644 --- a/src/apps/dashboard/forms.py +++ b/src/apps/dashboard/forms.py @@ -19,6 +19,12 @@ class ItemForm(forms.models.ModelForm): } error_messages = {"text": {"required": EMPTY_ITEM_ERROR}} + def is_valid(self): + result = super().is_valid() + if not result: + self.fields["text"].widget.attrs["class"] += " is-invalid" + return result + def save(self, for_list): self.instance.list = for_list return super().save() diff --git a/src/apps/dashboard/migrations/0005_alter_item_options.py b/src/apps/dashboard/migrations/0005_alter_item_options.py new file mode 100644 index 0000000..5fb1062 --- /dev/null +++ b/src/apps/dashboard/migrations/0005_alter_item_options.py @@ -0,0 +1,17 @@ +# Generated by Django 6.0 on 2026-01-24 17:54 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('dashboard', '0004_alter_item_unique_together'), + ] + + operations = [ + migrations.AlterModelOptions( + name='item', + options={'ordering': ('id',)}, + ), + ] diff --git a/src/apps/dashboard/models.py b/src/apps/dashboard/models.py index 890780f..d4e3e2c 100644 --- a/src/apps/dashboard/models.py +++ b/src/apps/dashboard/models.py @@ -4,11 +4,15 @@ from django.urls import reverse class List(models.Model): def get_absolute_url(self): return reverse("view_list", args=[self.id]) - class Item(models.Model): text = models.TextField(default="") list = models.ForeignKey(List, default=None, on_delete=models.CASCADE) class Meta: + ordering = ("id",) unique_together = ("list", "text") + + def __str__(self): + return self.text + diff --git a/src/apps/dashboard/tests/test_forms.py b/src/apps/dashboard/tests/test_forms.py index 557f66b..eafd4b5 100644 --- a/src/apps/dashboard/tests/test_forms.py +++ b/src/apps/dashboard/tests/test_forms.py @@ -23,6 +23,15 @@ class ItemFormTest(TestCase): self.assertFalse(form.is_valid()) self.assertEqual(form.errors["text"], [EMPTY_ITEM_ERROR]) + def test_invalid_form_has_bootstrap_is_invalid_css_class(self): + form = ItemForm(data={"text": ""}) + self.assertFalse(form.is_valid()) + field = form.fields["text"] + self.assertEqual( + field.widget.attrs["class"], + "form-control form-control-lg is-invalid", + ) + def test_form_save_handles_saving_to_a_list(self): mylist = List.objects.create() form = ItemForm(data={"text": "do re mi"}) diff --git a/src/apps/dashboard/tests/test_models.py b/src/apps/dashboard/tests/test_models.py index afb30a1..3408bee 100644 --- a/src/apps/dashboard/tests/test_models.py +++ b/src/apps/dashboard/tests/test_models.py @@ -41,7 +41,21 @@ class ItemModelTest(TestCase): item = Item(list=list2, text="nojk") item.full_clean() # should not raise + def test_string_representation(self): + item = Item(text="sample text") + self.assertEqual(str(item), "sample text") + class ListModelTest(TestCase): def test_get_absolute_url(self): mylist = List.objects.create() self.assertEqual(mylist.get_absolute_url(), f"/apps/dashboard/{mylist.id}/") + + def test_list_items_order(self): + list1 = List.objects.create() + item1 = Item.objects.create(list=list1, text="i1") + item2 = Item.objects.create(list=list1, text="item 2") + item3 = Item.objects.create(list=list1, text="3") + self.assertEqual( + list(list1.item_set.all()), + [item1, item2, item3], + ) diff --git a/src/apps/dashboard/views.py b/src/apps/dashboard/views.py index 57476e5..892d784 100644 --- a/src/apps/dashboard/views.py +++ b/src/apps/dashboard/views.py @@ -1,16 +1,15 @@ -from django.core.exceptions import ValidationError from django.shortcuts import redirect, render from .forms import ExistingListItemForm, ItemForm from .models import Item, List def home_page(request): - return render(request, 'apps/dashboard/home.html', {"form": ItemForm()}) + return render(request, "apps/dashboard/home.html", {"form": ItemForm()}) def new_list(request): form = ItemForm(data=request.POST) if form.is_valid(): nulist = List.objects.create() - Item.objects.create(text=request.POST["text"], list=nulist) + form.save(for_list=nulist) return redirect(nulist) else: return render(request, "apps/dashboard/home.html", {"form": form}) @@ -24,5 +23,5 @@ def view_list(request, list_id): if form.is_valid(): form.save() return redirect(our_list) - return render(request, 'apps/dashboard/list.html', {'list': our_list, "form": form}) + return render(request, "apps/dashboard/list.html", {"list": our_list, "form": form})