2014-05-20 05:27:09 +08:00
|
|
|
import datetime
|
|
|
|
|
2010-10-18 21:34:47 +08:00
|
|
|
from django.core.exceptions import ImproperlyConfigured
|
2013-12-23 23:01:13 +08:00
|
|
|
from django.test import TestCase, override_settings
|
2015-01-28 20:35:27 +08:00
|
|
|
from django.views.generic.base import View
|
2010-10-18 21:34:47 +08:00
|
|
|
|
2015-02-23 08:53:57 +08:00
|
|
|
from .models import Artist, Author, Book, Page
|
2011-10-14 05:34:56 +08:00
|
|
|
|
2010-10-18 21:34:47 +08:00
|
|
|
|
2014-04-05 14:04:46 +08:00
|
|
|
@override_settings(ROOT_URLCONF="generic_views.urls")
|
2010-10-18 21:34:47 +08:00
|
|
|
class ListViewTests(TestCase):
|
2015-02-23 08:53:57 +08:00
|
|
|
@classmethod
|
|
|
|
def setUpTestData(cls):
|
|
|
|
cls.artist1 = Artist.objects.create(name="Rene Magritte")
|
|
|
|
cls.author1 = Author.objects.create(
|
|
|
|
name="Roberto Bolaño", slug="roberto-bolano"
|
|
|
|
)
|
|
|
|
cls.author2 = Author.objects.create(
|
|
|
|
name="Scott Rosenberg", slug="scott-rosenberg"
|
|
|
|
)
|
|
|
|
cls.book1 = Book.objects.create(
|
|
|
|
name="2066", slug="2066", pages=800, pubdate=datetime.date(2008, 10, 1)
|
2022-02-04 03:24:19 +08:00
|
|
|
)
|
2015-02-23 08:53:57 +08:00
|
|
|
cls.book1.authors.add(cls.author1)
|
|
|
|
cls.book2 = Book.objects.create(
|
|
|
|
name="Dreaming in Code",
|
|
|
|
slug="dreaming-in-code",
|
|
|
|
pages=300,
|
|
|
|
pubdate=datetime.date(2006, 5, 1),
|
|
|
|
)
|
|
|
|
cls.page1 = Page.objects.create(
|
|
|
|
content="I was once bitten by a moose.",
|
|
|
|
template="generic_views/page_template.html",
|
|
|
|
)
|
2010-10-18 21:34:47 +08:00
|
|
|
|
|
|
|
def test_items(self):
|
|
|
|
res = self.client.get("/list/dict/")
|
|
|
|
self.assertEqual(res.status_code, 200)
|
|
|
|
self.assertTemplateUsed(res, "generic_views/list.html")
|
|
|
|
self.assertEqual(res.context["object_list"][0]["first"], "John")
|
|
|
|
|
|
|
|
def test_queryset(self):
|
|
|
|
res = self.client.get("/list/authors/")
|
|
|
|
self.assertEqual(res.status_code, 200)
|
|
|
|
self.assertTemplateUsed(res, "generic_views/author_list.html")
|
|
|
|
self.assertEqual(list(res.context["object_list"]), list(Author.objects.all()))
|
2013-05-21 17:42:15 +08:00
|
|
|
self.assertIsInstance(res.context["view"], View)
|
2011-02-14 21:04:51 +08:00
|
|
|
self.assertIs(res.context["author_list"], res.context["object_list"])
|
2010-10-28 10:58:28 +08:00
|
|
|
self.assertIsNone(res.context["paginator"])
|
|
|
|
self.assertIsNone(res.context["page_obj"])
|
|
|
|
self.assertFalse(res.context["is_paginated"])
|
2010-10-18 21:34:47 +08:00
|
|
|
|
|
|
|
def test_paginated_queryset(self):
|
|
|
|
self._make_authors(100)
|
|
|
|
res = self.client.get("/list/authors/paginated/")
|
|
|
|
self.assertEqual(res.status_code, 200)
|
|
|
|
self.assertTemplateUsed(res, "generic_views/author_list.html")
|
2010-10-28 10:58:28 +08:00
|
|
|
self.assertEqual(len(res.context["object_list"]), 30)
|
2011-02-14 21:04:51 +08:00
|
|
|
self.assertIs(res.context["author_list"], res.context["object_list"])
|
2010-10-28 10:58:28 +08:00
|
|
|
self.assertTrue(res.context["is_paginated"])
|
2010-10-18 21:34:47 +08:00
|
|
|
self.assertEqual(res.context["page_obj"].number, 1)
|
|
|
|
self.assertEqual(res.context["paginator"].num_pages, 4)
|
2011-02-14 21:04:51 +08:00
|
|
|
self.assertEqual(res.context["author_list"][0].name, "Author 00")
|
|
|
|
self.assertEqual(list(res.context["author_list"])[-1].name, "Author 29")
|
2010-10-18 21:34:47 +08:00
|
|
|
|
|
|
|
def test_paginated_queryset_shortdata(self):
|
2016-10-27 15:53:39 +08:00
|
|
|
# Short datasets also result in a paginated view.
|
2010-10-18 21:34:47 +08:00
|
|
|
res = self.client.get("/list/authors/paginated/")
|
|
|
|
self.assertEqual(res.status_code, 200)
|
|
|
|
self.assertTemplateUsed(res, "generic_views/author_list.html")
|
|
|
|
self.assertEqual(list(res.context["object_list"]), list(Author.objects.all()))
|
2011-02-14 21:04:51 +08:00
|
|
|
self.assertIs(res.context["author_list"], res.context["object_list"])
|
2011-01-08 21:15:44 +08:00
|
|
|
self.assertEqual(res.context["page_obj"].number, 1)
|
|
|
|
self.assertEqual(res.context["paginator"].num_pages, 1)
|
2011-03-15 16:24:31 +08:00
|
|
|
self.assertFalse(res.context["is_paginated"])
|
2010-10-18 21:34:47 +08:00
|
|
|
|
|
|
|
def test_paginated_get_page_by_query_string(self):
|
|
|
|
self._make_authors(100)
|
|
|
|
res = self.client.get("/list/authors/paginated/", {"page": "2"})
|
|
|
|
self.assertEqual(res.status_code, 200)
|
|
|
|
self.assertTemplateUsed(res, "generic_views/author_list.html")
|
2010-10-28 10:58:28 +08:00
|
|
|
self.assertEqual(len(res.context["object_list"]), 30)
|
2011-02-14 21:04:51 +08:00
|
|
|
self.assertIs(res.context["author_list"], res.context["object_list"])
|
|
|
|
self.assertEqual(res.context["author_list"][0].name, "Author 30")
|
2010-10-18 21:34:47 +08:00
|
|
|
self.assertEqual(res.context["page_obj"].number, 2)
|
|
|
|
|
|
|
|
def test_paginated_get_last_page_by_query_string(self):
|
|
|
|
self._make_authors(100)
|
|
|
|
res = self.client.get("/list/authors/paginated/", {"page": "last"})
|
|
|
|
self.assertEqual(res.status_code, 200)
|
2010-10-28 10:58:28 +08:00
|
|
|
self.assertEqual(len(res.context["object_list"]), 10)
|
2011-02-14 21:04:51 +08:00
|
|
|
self.assertIs(res.context["author_list"], res.context["object_list"])
|
|
|
|
self.assertEqual(res.context["author_list"][0].name, "Author 90")
|
2010-10-18 21:34:47 +08:00
|
|
|
self.assertEqual(res.context["page_obj"].number, 4)
|
|
|
|
|
|
|
|
def test_paginated_get_page_by_urlvar(self):
|
|
|
|
self._make_authors(100)
|
|
|
|
res = self.client.get("/list/authors/paginated/3/")
|
|
|
|
self.assertEqual(res.status_code, 200)
|
|
|
|
self.assertTemplateUsed(res, "generic_views/author_list.html")
|
2010-10-28 10:58:28 +08:00
|
|
|
self.assertEqual(len(res.context["object_list"]), 30)
|
2011-02-14 21:04:51 +08:00
|
|
|
self.assertIs(res.context["author_list"], res.context["object_list"])
|
|
|
|
self.assertEqual(res.context["author_list"][0].name, "Author 60")
|
2010-10-18 21:34:47 +08:00
|
|
|
self.assertEqual(res.context["page_obj"].number, 3)
|
|
|
|
|
|
|
|
def test_paginated_page_out_of_range(self):
|
|
|
|
self._make_authors(100)
|
|
|
|
res = self.client.get("/list/authors/paginated/42/")
|
|
|
|
self.assertEqual(res.status_code, 404)
|
|
|
|
|
|
|
|
def test_paginated_invalid_page(self):
|
|
|
|
self._make_authors(100)
|
|
|
|
res = self.client.get("/list/authors/paginated/?page=frog")
|
|
|
|
self.assertEqual(res.status_code, 404)
|
|
|
|
|
2010-12-05 12:32:36 +08:00
|
|
|
def test_paginated_custom_paginator_class(self):
|
|
|
|
self._make_authors(7)
|
|
|
|
res = self.client.get("/list/authors/paginated/custom_class/")
|
|
|
|
self.assertEqual(res.status_code, 200)
|
2011-01-08 21:15:44 +08:00
|
|
|
self.assertEqual(res.context["paginator"].num_pages, 1)
|
2010-12-05 12:32:36 +08:00
|
|
|
# Custom pagination allows for 2 orphans on a page size of 5
|
|
|
|
self.assertEqual(len(res.context["object_list"]), 7)
|
|
|
|
|
2012-10-25 20:19:53 +08:00
|
|
|
def test_paginated_custom_page_kwarg(self):
|
|
|
|
self._make_authors(100)
|
|
|
|
res = self.client.get(
|
|
|
|
"/list/authors/paginated/custom_page_kwarg/", {"pagina": "2"}
|
|
|
|
)
|
|
|
|
self.assertEqual(res.status_code, 200)
|
|
|
|
self.assertTemplateUsed(res, "generic_views/author_list.html")
|
|
|
|
self.assertEqual(len(res.context["object_list"]), 30)
|
|
|
|
self.assertIs(res.context["author_list"], res.context["object_list"])
|
|
|
|
self.assertEqual(res.context["author_list"][0].name, "Author 30")
|
|
|
|
self.assertEqual(res.context["page_obj"].number, 2)
|
|
|
|
|
2010-12-05 12:32:36 +08:00
|
|
|
def test_paginated_custom_paginator_constructor(self):
|
|
|
|
self._make_authors(7)
|
|
|
|
res = self.client.get("/list/authors/paginated/custom_constructor/")
|
|
|
|
self.assertEqual(res.status_code, 200)
|
|
|
|
# Custom pagination allows for 2 orphans on a page size of 5
|
|
|
|
self.assertEqual(len(res.context["object_list"]), 7)
|
|
|
|
|
2012-11-21 11:45:38 +08:00
|
|
|
def test_paginated_orphaned_queryset(self):
|
|
|
|
self._make_authors(92)
|
|
|
|
res = self.client.get("/list/authors/paginated-orphaned/")
|
|
|
|
self.assertEqual(res.status_code, 200)
|
|
|
|
self.assertEqual(res.context["page_obj"].number, 1)
|
|
|
|
res = self.client.get("/list/authors/paginated-orphaned/", {"page": "last"})
|
|
|
|
self.assertEqual(res.status_code, 200)
|
|
|
|
self.assertEqual(res.context["page_obj"].number, 3)
|
|
|
|
res = self.client.get("/list/authors/paginated-orphaned/", {"page": "3"})
|
|
|
|
self.assertEqual(res.status_code, 200)
|
|
|
|
self.assertEqual(res.context["page_obj"].number, 3)
|
|
|
|
res = self.client.get("/list/authors/paginated-orphaned/", {"page": "4"})
|
|
|
|
self.assertEqual(res.status_code, 404)
|
|
|
|
|
2010-12-09 10:34:14 +08:00
|
|
|
def test_paginated_non_queryset(self):
|
|
|
|
res = self.client.get("/list/dict/paginated/")
|
2012-11-21 11:45:38 +08:00
|
|
|
|
2010-12-09 10:34:14 +08:00
|
|
|
self.assertEqual(res.status_code, 200)
|
|
|
|
self.assertEqual(len(res.context["object_list"]), 1)
|
|
|
|
|
2011-01-03 21:15:58 +08:00
|
|
|
def test_verbose_name(self):
|
|
|
|
res = self.client.get("/list/artists/")
|
|
|
|
self.assertEqual(res.status_code, 200)
|
|
|
|
self.assertTemplateUsed(res, "generic_views/list.html")
|
|
|
|
self.assertEqual(list(res.context["object_list"]), list(Artist.objects.all()))
|
2011-02-14 21:04:51 +08:00
|
|
|
self.assertIs(res.context["artist_list"], res.context["object_list"])
|
2011-01-03 21:15:58 +08:00
|
|
|
self.assertIsNone(res.context["paginator"])
|
|
|
|
self.assertIsNone(res.context["page_obj"])
|
|
|
|
self.assertFalse(res.context["is_paginated"])
|
|
|
|
|
2010-10-18 21:34:47 +08:00
|
|
|
def test_allow_empty_false(self):
|
|
|
|
res = self.client.get("/list/authors/notempty/")
|
|
|
|
self.assertEqual(res.status_code, 200)
|
|
|
|
Author.objects.all().delete()
|
|
|
|
res = self.client.get("/list/authors/notempty/")
|
|
|
|
self.assertEqual(res.status_code, 404)
|
|
|
|
|
|
|
|
def test_template_name(self):
|
|
|
|
res = self.client.get("/list/authors/template_name/")
|
|
|
|
self.assertEqual(res.status_code, 200)
|
|
|
|
self.assertEqual(list(res.context["object_list"]), list(Author.objects.all()))
|
2011-02-14 21:04:51 +08:00
|
|
|
self.assertIs(res.context["author_list"], res.context["object_list"])
|
2010-10-18 21:34:47 +08:00
|
|
|
self.assertTemplateUsed(res, "generic_views/list.html")
|
|
|
|
|
|
|
|
def test_template_name_suffix(self):
|
|
|
|
res = self.client.get("/list/authors/template_name_suffix/")
|
|
|
|
self.assertEqual(res.status_code, 200)
|
|
|
|
self.assertEqual(list(res.context["object_list"]), list(Author.objects.all()))
|
2011-02-14 21:04:51 +08:00
|
|
|
self.assertIs(res.context["author_list"], res.context["object_list"])
|
2010-10-18 21:34:47 +08:00
|
|
|
self.assertTemplateUsed(res, "generic_views/author_objects.html")
|
|
|
|
|
|
|
|
def test_context_object_name(self):
|
|
|
|
res = self.client.get("/list/authors/context_object_name/")
|
|
|
|
self.assertEqual(res.status_code, 200)
|
|
|
|
self.assertEqual(list(res.context["object_list"]), list(Author.objects.all()))
|
2010-10-28 10:58:28 +08:00
|
|
|
self.assertNotIn("authors", res.context)
|
|
|
|
self.assertIs(res.context["author_list"], res.context["object_list"])
|
2010-10-18 21:34:47 +08:00
|
|
|
self.assertTemplateUsed(res, "generic_views/author_list.html")
|
|
|
|
|
|
|
|
def test_duplicate_context_object_name(self):
|
|
|
|
res = self.client.get("/list/authors/dupe_context_object_name/")
|
|
|
|
self.assertEqual(res.status_code, 200)
|
|
|
|
self.assertEqual(list(res.context["object_list"]), list(Author.objects.all()))
|
2010-10-28 10:58:28 +08:00
|
|
|
self.assertNotIn("authors", res.context)
|
|
|
|
self.assertNotIn("author_list", res.context)
|
2010-10-18 21:34:47 +08:00
|
|
|
self.assertTemplateUsed(res, "generic_views/author_list.html")
|
|
|
|
|
|
|
|
def test_missing_items(self):
|
2017-05-29 03:37:21 +08:00
|
|
|
msg = (
|
|
|
|
"AuthorList is missing a QuerySet. Define AuthorList.model, "
|
|
|
|
"AuthorList.queryset, or override AuthorList.get_queryset()."
|
|
|
|
)
|
|
|
|
with self.assertRaisesMessage(ImproperlyConfigured, msg):
|
2016-01-17 19:26:39 +08:00
|
|
|
self.client.get("/list/authors/invalid/")
|
2010-10-18 21:34:47 +08:00
|
|
|
|
2017-10-17 21:22:45 +08:00
|
|
|
def test_invalid_get_queryset(self):
|
|
|
|
msg = (
|
|
|
|
"AuthorListGetQuerysetReturnsNone requires either a 'template_name' "
|
|
|
|
"attribute or a get_queryset() method that returns a QuerySet."
|
|
|
|
)
|
|
|
|
with self.assertRaisesMessage(ImproperlyConfigured, msg):
|
|
|
|
self.client.get("/list/authors/get_queryset/")
|
|
|
|
|
2012-05-17 19:29:52 +08:00
|
|
|
def test_paginated_list_view_does_not_load_entire_table(self):
|
|
|
|
# Regression test for #17535
|
|
|
|
self._make_authors(3)
|
|
|
|
# 1 query for authors
|
|
|
|
with self.assertNumQueries(1):
|
|
|
|
self.client.get("/list/authors/notempty/")
|
|
|
|
# same as above + 1 query to test if authors exist + 1 query for pagination
|
|
|
|
with self.assertNumQueries(3):
|
|
|
|
self.client.get("/list/authors/notempty/paginated/")
|
|
|
|
|
2014-05-20 05:27:09 +08:00
|
|
|
def test_explicitly_ordered_list_view(self):
|
|
|
|
Book.objects.create(
|
|
|
|
name="Zebras for Dummies", pages=800, pubdate=datetime.date(2006, 9, 1)
|
2022-02-04 03:24:19 +08:00
|
|
|
)
|
2014-05-20 05:27:09 +08:00
|
|
|
res = self.client.get("/list/books/sorted/")
|
|
|
|
self.assertEqual(res.status_code, 200)
|
|
|
|
self.assertEqual(res.context["object_list"][0].name, "2066")
|
|
|
|
self.assertEqual(res.context["object_list"][1].name, "Dreaming in Code")
|
|
|
|
self.assertEqual(res.context["object_list"][2].name, "Zebras for Dummies")
|
|
|
|
|
|
|
|
res = self.client.get("/list/books/sortedbypagesandnamedec/")
|
|
|
|
self.assertEqual(res.status_code, 200)
|
|
|
|
self.assertEqual(res.context["object_list"][0].name, "Dreaming in Code")
|
|
|
|
self.assertEqual(res.context["object_list"][1].name, "Zebras for Dummies")
|
|
|
|
self.assertEqual(res.context["object_list"][2].name, "2066")
|
|
|
|
|
2012-11-05 07:46:30 +08:00
|
|
|
@override_settings(DEBUG=True)
|
|
|
|
def test_paginated_list_view_returns_useful_message_on_invalid_page(self):
|
|
|
|
# test for #19240
|
|
|
|
# tests that source exception's message is included in page
|
|
|
|
self._make_authors(1)
|
|
|
|
res = self.client.get("/list/authors/paginated/2/")
|
|
|
|
self.assertEqual(res.status_code, 404)
|
2017-01-12 06:17:25 +08:00
|
|
|
self.assertEqual(
|
|
|
|
res.context.get("reason"), "Invalid page (2): That page contains no results"
|
|
|
|
)
|
2012-11-05 07:46:30 +08:00
|
|
|
|
2010-10-18 21:34:47 +08:00
|
|
|
def _make_authors(self, n):
|
|
|
|
Author.objects.all().delete()
|
|
|
|
for i in range(n):
|
|
|
|
Author.objects.create(name="Author %02i" % i, slug="a%s" % i)
|