1
1
[[chapter_15_advanced_forms]]
2
- More Advanced Forms
3
- -------------------
2
+ == More Advanced Forms
4
3
5
4
.🚧 Warning, Chapter update in progress
6
5
*******************************************************************************
@@ -26,8 +25,7 @@ want to skip ahead, that's OK too. Make sure you take a quick look at the aside
26
25
on developer stupidity, and the recap on testing views at the end.
27
26
28
27
29
- Another FT for Duplicate Items
30
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
28
+ === Another FT for Duplicate Items
31
29
32
30
33
31
@@ -67,7 +65,7 @@ enough that it's practical to keep them in different methods:
67
65
68
66
[subs="specialcharacters,macros"]
69
67
----
70
- $ pass:quotes[*python manage.py test functional_tests.test_list_item_validation*]
68
+ $ pass:quotes[*python manage.py test functional_tests.test_list_item_validation*]
71
69
[...]
72
70
selenium.common.exceptions.NoSuchElementException: Message: Unable to locate
73
71
element: .has-error
@@ -81,15 +79,14 @@ just the failing one, I hear you ask? Why, yes indeed:
81
79
[subs="specialcharacters,macros"]
82
80
----
83
81
$ pass:quotes[*python manage.py test functional_tests.\
84
- test_list_item_validation.ItemValidationTest.test_cannot_add_duplicate_items*]
82
+ test_list_item_validation.ItemValidationTest.test_cannot_add_duplicate_items*]
85
83
[...]
86
84
selenium.common.exceptions.NoSuchElementException: Message: Unable to locate
87
85
element: .has-error
88
86
----
89
87
90
88
91
- Preventing Duplicates at the Model Layer
92
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
89
+ ==== Preventing Duplicates at the Model Layer
93
90
94
91
95
92
((("model-layer validation", "preventing duplicate items")))Here's
@@ -110,7 +107,7 @@ def test_duplicate_items_are_invalid(self):
110
107
----
111
108
====
112
109
113
- And, while it occurs to us, we add another test to make sure we don't
110
+ And, while it occurs to us, we add another test to make sure we don't
114
111
overdo it on our integrity constraints:
115
112
116
113
@@ -128,7 +125,7 @@ def test_CAN_save_same_item_to_different_lists(self):
128
125
----
129
126
====
130
127
131
- I always like to put a little comment for tests which are checking
128
+ I always like to put a little comment for tests which are checking
132
129
that a particular use case should 'not' raise an error; otherwise,
133
130
it can be hard to see what's being tested:
134
131
@@ -228,13 +225,12 @@ class Item(models.Model):
228
225
----
229
226
====
230
227
231
- You might want to take a quick peek at the
228
+ You might want to take a quick peek at the
232
229
https://docs.djangoproject.com/en/1.11/ref/models/options/[Django docs on model
233
230
`Meta` attributes] at this point.
234
231
235
232
236
- A Little Digression on Queryset Ordering and String Representations
237
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
233
+ ==== A Little Digression on Queryset Ordering and String Representations
238
234
239
235
//TODO: actually, this error will never appear with the new migrations
240
236
// framework. could drop this whole section?
425
421
// TODO: in theory we should do a migration now.
426
422
427
423
[[rewrite-model-test]]
428
- Rewriting the Old Model Test
429
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
424
+ ==== Rewriting the Old Model Test
430
425
431
426
432
427
That long-winded model test did serendipitously help us find an unexpected
433
428
bug, but now it's time to rewrite it. I wrote it in a very verbose style to
434
429
introduce the Django ORM, but in fact, now that we have the explicit test for
435
- ordering, we can get the same coverage from a couple of much shorter tests.
430
+ ordering, we can get the same coverage from a couple of much shorter tests.
436
431
Delete `test_saving_and_retrieving_items` and replace with this:
437
432
438
433
[role="sourcecode"]
@@ -456,7 +451,7 @@ class ListAndItemModelsTest(TestCase):
456
451
[...]
457
452
----
458
453
====
459
-
454
+
460
455
That's more than enough really--a check of the default values of attributes
461
456
on a freshly initialized model object is enough to sanity-check that we've
462
457
probably set some fields up in 'models.py'. The "item is related to list" test
494
489
----
495
490
496
491
497
- Some Integrity Errors Do Show Up on Save
498
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
492
+ ==== Some Integrity Errors Do Show Up on Save
499
493
500
494
501
495
@@ -505,7 +499,7 @@ final aside before we move on. Do you remember I mentioned in
505
499
on save? It all depends on whether the integrity constraint is actually being
506
500
enforced by the database.
507
501
508
- Try running `makemigrations` and you'll see that Django wants to add the
502
+ Try running `makemigrations` and you'll see that Django wants to add the
509
503
`unique_together` constraint to the database itself, rather than just having
510
504
it as an application-layer constraint:
511
505
@@ -577,8 +571,7 @@ $ pass:[<strong>git commit -am "Implement duplicate item validation at model lay
577
571
----
578
572
579
573
580
- Experimenting with Duplicate Item Validation at the Views Layer
581
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
574
+ === Experimenting with Duplicate Item Validation at the Views Layer
582
575
583
576
584
577
((("duplicate items testing", "at the views layer", secondary-sortas="views layer")))Let's
@@ -648,8 +641,7 @@ from unittest import skip
648
641
====
649
642
650
643
651
- A More Complex Form to Handle Uniqueness Validation
652
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
644
+ === A More Complex Form to Handle Uniqueness Validation
653
645
654
646
((("duplicate items testing", "complex form for")))((("uniqueness validation", seealso="duplicate items testing")))The
655
647
form to create a new list only needs to know one thing, the new item text.
@@ -695,7 +687,7 @@ class ExistingListItemFormTest(TestCase):
695
687
====
696
688
697
689
Next we iterate through a few TDD cycles until we get a form with a
698
- custom constructor, which just ignores its `for_list` argument.
690
+ custom constructor, which just ignores its `for_list` argument.
699
691
(I won't show them all, but I'm sure you'll do them, right? Remember, the Goat
700
692
sees all.)
701
693
@@ -742,7 +734,7 @@ AssertionError: True is not false
742
734
----
743
735
744
736
The next step requires a little knowledge of Django's internals, but you
745
- can read up on it in the Django docs on
737
+ can read up on it in the Django docs on
746
738
https://docs.djangoproject.com/en/1.11/ref/models/instances/#validating-objects[model
747
739
validation] and
748
740
https://docs.djangoproject.com/en/1.11/ref/forms/validation/[form validation].
@@ -788,8 +780,7 @@ $ *git commit -a*
788
780
----
789
781
790
782
791
- Using the Existing List Item Form in the List View
792
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
783
+ === Using the Existing List Item Form in the List View
793
784
794
785
((("duplicate items testing", "in the list view", secondary-sortas="list view", id="DITlist15")))Now
795
786
let's see if we can put this form to work in our view.
@@ -879,7 +870,7 @@ And that 'almost' fixes everything, except for an unexpected fail:
879
870
TypeError: save() missing 1 required positional argument: 'for_list'
880
871
----
881
872
882
- Our custom save method from the parent `ItemForm` is no longer needed.
873
+ Our custom save method from the parent `ItemForm` is no longer needed.
883
874
Let's make a quick unit test for that:
884
875
885
876
//IDEA: add the form class names here so ppl know which test_form_save and save()
@@ -961,14 +952,13 @@ testing views over the last few chapters.((("", startref="DITlist15")))
961
952
962
953
963
954
964
- Wrapping Up: What We've Learned About Testing Django
965
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
955
+ === Wrapping Up: What We've Learned About Testing Django
966
956
967
957
((("class-based generic views (CBGVs)", "key tests and assertions")))((("Django framework", "class-based generic views")))We're
968
958
now at a point where our app looks a lot more like a "standard"
969
959
Django app, and it implements the three common Django layers: models,
970
960
forms, and views. We no longer have any "training wheels”-style tests,
971
- and our code looks pretty much like code we'd be happy to see in a
961
+ and our code looks pretty much like code we'd be happy to see in a
972
962
real app.
973
963
974
964
We have one unit test file for each of our key source code files. Here's
0 commit comments