@@ -1571,11 +1571,11 @@ https://docs.python.org/3/reference/lexical_analysis.html#f-strings[docs]
1571
1571
Running the unit tests gives an expected 404, and another related error:
1572
1572
1573
1573
----
1574
- FAIL: test_displays_only_items_for_that_list (lists.tests.ListViewTest)
1574
+ FAIL: test_displays_only_items_for_that_list
1575
1575
AssertionError: 404 != 200 : Couldn't retrieve content: Response code was 404
1576
1576
(expected 200)
1577
1577
[...]
1578
- FAIL: test_uses_list_template (lists.tests.ListViewTest)
1578
+ FAIL: test_uses_list_template
1579
1579
AssertionError: No templates used to render the response
1580
1580
----
1581
1581
@@ -1595,7 +1595,7 @@ It's time to learn how we can pass parameters from URLs to views:
1595
1595
urlpatterns = [
1596
1596
path('', views.home_page, name='home'),
1597
1597
path('lists/new', views.new_list, name='new_list'),
1598
- path('lists/<list_id>/', views.view_list, name='view_list'),
1598
+ path('lists/<int: list_id>/', views.view_list, name='view_list'),
1599
1599
]
1600
1600
----
1601
1601
====
@@ -1614,18 +1614,20 @@ If we go to '/lists/foo/', we get `view_list(request, "foo")`.
1614
1614
But our view doesn't expect an argument yet! Sure enough, this causes problems:
1615
1615
1616
1616
----
1617
- ERROR: test_displays_only_items_for_that_list (lists.tests.ListViewTest)
1617
+ ERROR: test_displays_only_items_for_that_list
1618
1618
[...]
1619
- TypeError: view_list() takes 1 positional argument but 2 were given
1619
+ TypeError: view_list() got an unexpected keyword argument 'list_id'
1620
1620
[...]
1621
- ERROR: test_uses_list_template (lists.tests.ListViewTest)
1621
+ ERROR: test_uses_list_template
1622
1622
[...]
1623
- TypeError: view_list() takes 1 positional argument but 2 were given
1623
+ TypeError: view_list() got an unexpected keyword argument 'list_id'
1624
1624
[...]
1625
- ERROR : test_redirects_after_POST (lists.tests.NewListTest)
1625
+ FAIL : test_redirects_after_POST
1626
1626
[...]
1627
- TypeError: view_list() takes 1 positional argument but 2 were given
1628
- FAILED (errors=3)
1627
+ AssertionError: 404 != 200 : Couldn't retrieve redirection page
1628
+ '/lists/the-only-list-in-the-world/': response code was 404 (expected 200)
1629
+ [...]
1630
+ FAILED (failures=1, errors=2)
1629
1631
----
1630
1632
1631
1633
We can fix that easily with a dummy parameter in 'views.py' :
@@ -1643,7 +1645,7 @@ def view_list(request, list_id):
1643
1645
Now we're down to our expected failure:
1644
1646
1645
1647
----
1646
- FAIL: test_displays_only_items_for_that_list (lists.tests.ListViewTest)
1648
+ FAIL: test_displays_only_items_for_that_list
1647
1649
[...]
1648
1650
AssertionError: 1 != 0 : Response should not contain 'other list item 1'
1649
1651
----
@@ -1669,12 +1671,13 @@ def view_list(request, list_id):
1669
1671
Adjusting new_list to the New World
1670
1672
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1671
1673
1672
- Oops, now we get errors in another test:
1674
+ Oops, now we get a failure in another test:
1673
1675
1674
1676
----
1675
- ERROR: test_redirects_after_POST (lists.tests.NewListTest)
1676
- ValueError: invalid literal for int() with base 10:
1677
- 'the-only-list-in-the-world'
1677
+ FAIL: test_redirects_after_POST
1678
+
1679
+ AssertionError: 404 != 200 : Couldn't retrieve redirection page
1680
+ '/lists/the-only-list-in-the-world/': response code was 404 (expected 200)
1678
1681
----
1679
1682
1680
1683
Let's take a look at this test then, since it's moaning:
@@ -1756,7 +1759,7 @@ Well, almost:
1756
1759
F.
1757
1760
======================================================================
1758
1761
FAIL: test_can_start_a_list_for_one_user
1759
- (functional_tests.tests.NewVisitorTest)
1762
+ (functional_tests.tests.NewVisitorTest.test_can_start_a_list_for_one_user )
1760
1763
---------------------------------------------------------------------
1761
1764
Traceback (most recent call last):
1762
1765
File "...python-tdd-book/functional_tests/tests.py", line 68, in
@@ -1842,44 +1845,20 @@ NOTE: Are you wondering about `other_list`? A bit like in the tests for
1842
1845
of those, after all). It's a judgement call, but this one feels worth it.
1843
1846
There's some more discussion of this in <<testing-for-stupidity>>.
1844
1847
1845
- We get:
1848
+
1849
+ And that fails as expected, the list item is not saved,
1850
+ and the new URL currently returns a 404:
1846
1851
1847
1852
----
1848
1853
AssertionError: 0 != 1
1849
1854
[...]
1850
- AssertionError: 301 != 302 : Response didn't redirect as expected: Response
1851
- code was 301 (expected 302)
1855
+ AssertionError: 404 != 302 : Response didn't redirect as expected: Response
1856
+ code was 404 (expected 302)
1852
1857
----
1853
1858
1859
+ ////
1860
+ (old code
1854
1861
1855
- Beware of Greedy Regular Expressions!
1856
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1857
-
1858
-
1859
- ((("regular expressions")))((("greedy regular expressions"))) That's
1860
- a little strange. We haven't actually specified a URL for
1861
- '/lists/1/add_item' yet, so our expected failure is `404 != 302` . Why are we
1862
- getting a 301?
1863
-
1864
- This was a bit of a puzzler! It's because we've used a very "greedy"
1865
- capture group in our URL:
1866
-
1867
-
1868
- [role="sourcecode currentcontents"]
1869
- .superlists/urls.py
1870
- ====
1871
- [source,python]
1872
- ----
1873
- path('lists/<list_id>/', views.view_list, name='view_list'),
1874
- ----
1875
- ====
1876
-
1877
- ((("HTML", "POST requests", "redirect following")))((("POST requests", "redirect following")))((("permanent redirect (301)"))) Django
1878
- has some built-in code to issue a permanent redirect (301) whenever
1879
- someone asks for a URL which is 'almost' right, except for a missing slash.
1880
- In this case, [keep-together]#'/lists/1/add_item/'# would be a match for
1881
- `lists/(.+)/` , with the `(.+)` capturing `1/add_item` . So Django "helpfully"
1882
- guesses that we actually wanted the URL with a trailing slash.
1883
1862
1884
1863
We can fix that by making our URL pattern explicitly capture only numerical
1885
1864
digits, by using the prefix `int:` :
@@ -1894,20 +1873,12 @@ digits, by using the prefix `int:`:
1894
1873
====
1895
1874
//38
1896
1875
1897
- That gives us the failure we expected:
1876
+ ////
1898
1877
1899
- ----
1900
- AssertionError: 0 != 1
1901
- [...]
1902
- AssertionError: 404 != 302 : Response didn't redirect as expected: Response
1903
- code was 404 (expected 302)
1904
- ----
1905
1878
1906
1879
The Last New URL
1907
1880
^^^^^^^^^^^^^^^^
1908
1881
1909
-
1910
-
1911
1882
Now we've got our expected 404, let's add a new URL for adding new items to
1912
1883
existing lists:
1913
1884
@@ -1917,10 +1888,10 @@ existing lists:
1917
1888
[source,python]
1918
1889
----
1919
1890
urlpatterns = [
1920
- url(r'^$ ', views.home_page, name='home'),
1921
- url(r'^ lists/new$ ', views.new_list, name='new_list'),
1922
- url(r'^ lists/(\d+)/$ ', views.view_list, name='view_list'),
1923
- url(r'^ lists/(\d+) /add_item$ ', views.add_item, name='add_item'),
1891
+ path(' ', views.home_page, name='home'),
1892
+ path(' lists/new', views.new_list, name='new_list'),
1893
+ path(' lists/<int:list_id>/ ', views.view_list, name='view_list'),
1894
+ path(' lists/<int:list_id> /add_item', views.add_item, name='add_item'),
1924
1895
]
1925
1896
----
1926
1897
====
@@ -1964,7 +1935,7 @@ def add_item(request):
1964
1935
Aha:
1965
1936
1966
1937
----
1967
- TypeError: add_item() takes 1 positional argument but 2 were given
1938
+ TypeError: add_item() got an unexpected keyword argument 'list_id'
1968
1939
----
1969
1940
1970
1941
@@ -2113,7 +2084,7 @@ That, of course, will break one of our old tests, because the template
2113
2084
needed `items` :
2114
2085
2115
2086
----
2116
- FAIL: test_displays_only_items_for_that_list (lists.tests.ListViewTest)
2087
+ FAIL: test_displays_only_items_for_that_list
2117
2088
[...]
2118
2089
AssertionError: False is not true : Couldn't find 'itemey 1' in response
2119
2090
----
@@ -2244,13 +2215,13 @@ of our three URLs, and none of the other stuff from the parent 'urls.py':
2244
2215
====
2245
2216
[source,python]
2246
2217
----
2247
- from django.conf. urls import url
2218
+ from django.urls import path
2248
2219
from lists import views
2249
2220
2250
2221
urlpatterns = [
2251
- url(r'^ new$ ', views.new_list, name='new_list'),
2252
- url(r'^(\d+)/$ ', views.view_list, name='view_list'),
2253
- url(r'^(\d+)/ add_item$ ', views.add_item, name='add_item'),
2222
+ path('lists/ new', views.new_list, name='new_list'),
2223
+ path('lists/<int:list_id>/ ', views.view_list, name='view_list'),
2224
+ path('lists/<int:list_id>/ add_item', views.add_item, name='add_item'),
2254
2225
]
2255
2226
----
2256
2227
====
0 commit comments