From a8ff69a2b0d65078e0f94655983f3ab6833c7464 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Sun, 30 Mar 2014 21:21:02 +0100 Subject: [PATCH 01/10] Added PageQuerySet --- wagtail/wagtailcore/models.py | 3 ++ wagtail/wagtailcore/query.py | 76 +++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 wagtail/wagtailcore/query.py diff --git a/wagtail/wagtailcore/models.py b/wagtail/wagtailcore/models.py index b06137b9df..9def327d61 100644 --- a/wagtail/wagtailcore/models.py +++ b/wagtail/wagtailcore/models.py @@ -14,6 +14,7 @@ from django.template.response import TemplateResponse from django.utils.translation import ugettext_lazy as _ from wagtail.wagtailcore.util import camelcase_to_underscore +from wagtail.wagtailcore.query import PageQuerySet from wagtail.wagtailsearch import Indexed, get_search_backend @@ -138,6 +139,8 @@ class PageBase(models.base.ModelBase): # don't proceed with all this page type registration stuff return + cls.query = PageQuerySet(model=cls) + if 'template' not in dct: # Define a default template path derived from the app name and model name cls.template = "%s/%s.html" % (cls._meta.app_label, camelcase_to_underscore(name)) diff --git a/wagtail/wagtailcore/query.py b/wagtail/wagtailcore/query.py new file mode 100644 index 0000000000..faffa1a904 --- /dev/null +++ b/wagtail/wagtailcore/query.py @@ -0,0 +1,76 @@ +from django.db.models.query import QuerySet +from django.db.models import Q +from django.contrib.contenttypes.models import ContentType + + +class PageQuerySet(QuerySet): + """ + Defines some extra query set methods that are useful for pages. + """ + def live_q(self): + return Q(live=True) + + def live(self): + return self.filter(self.live_q()) + + def not_live(self): + return self.exclude(self.live_q()) + + def descendant_of_q(self, other): + return Q(path__startswith=other.path) & Q(depth__gt=other.depth) + + def descendant_of(self, other): + return self.filter(self.descendant_of_q(other)) + + def not_descendant_of(self, other): + return self.exclude(self.descendant_of_q(other)) + + def child_of_q(self, other): + return self.descendant_of_q(other) & Q(depth=other.depth + 1) + + def child_of(self, other): + return self.filter(self.child_of_q(other)) + + def not_child_of(self, other): + return self.exclude(self.child_of_q(other)) + + def ascendant_of_q(self, other): + paths = [ + other.path[0:pos] + for pos in range(0, len(other.path), other.steplen)[1:] + ] + return Q(path__in=paths) + + def ascendant_of(self, other): + return self.filter(self.ascendant_of_q(other)) + + def not_ascendant_of(self, other): + return self.exclude(self.ascendant_of_q(other)) + + def parent_of_q(self, other): + return Q(path=self.model._get_parent_path_from_path(other.path)) + + def parent_of(self, other): + return self.filter(self.parent_of_q(other)) + + def not_parent_of(self, other): + return self.exclude(self.parent_of_q(other)) + + def sibling_of_q(self, other): + return Q(path__startswith=self.model._get_parent_path_from_path(other.path)) & Q(depth=other.depth) + + def sibling_of(self, other): + return self.filter(self.sibling_of_q(other)) + + def not_sibling_of(self, other): + return self.exclude(self.sibling_of_q(other)) + + def type_q(self, model): + content_type = ContentType.objects.get_for_model(model) + return Q(content_type=content_type) + + def type(self, model): + return self.filter(self.type_q(model)) + + def not_type(self, model): + return self.exclude(self.type_q(model)) From a307393c2b1c49cbbf39ad0f22752fabe6b23a17 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Mon, 7 Apr 2014 15:38:02 +0100 Subject: [PATCH 02/10] Added 'page' attribute to PageQuerySet --- wagtail/wagtailcore/query.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/wagtail/wagtailcore/query.py b/wagtail/wagtailcore/query.py index faffa1a904..3365700c93 100644 --- a/wagtail/wagtailcore/query.py +++ b/wagtail/wagtailcore/query.py @@ -16,6 +16,15 @@ class PageQuerySet(QuerySet): def not_live(self): return self.exclude(self.live_q()) + def page_q(self, other): + return Q(id=other.id) + + def page(self, other): + return self.filter(self.page_q(other)) + + def not_page(self, other): + return self.exclude(self.page_q(other)) + def descendant_of_q(self, other): return Q(path__startswith=other.path) & Q(depth__gt=other.depth) From 90a06950761342b84ce60c826b0cafea5ca22381 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Mon, 7 Apr 2014 15:38:42 +0100 Subject: [PATCH 03/10] Added inclusive flag to ascendent_of, descendant_of and sibling_of --- wagtail/wagtailcore/query.py | 53 +++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/wagtail/wagtailcore/query.py b/wagtail/wagtailcore/query.py index 3365700c93..134ddbdcf9 100644 --- a/wagtail/wagtailcore/query.py +++ b/wagtail/wagtailcore/query.py @@ -25,14 +25,19 @@ class PageQuerySet(QuerySet): def not_page(self, other): return self.exclude(self.page_q(other)) - def descendant_of_q(self, other): - return Q(path__startswith=other.path) & Q(depth__gt=other.depth) + def descendant_of_q(self, other, inclusive=False): + q = Q(path__startswith=other.path) & Q(depth__gte=other.depth) - def descendant_of(self, other): - return self.filter(self.descendant_of_q(other)) + if not inclusive: + q &= ~self.page_q(other) - def not_descendant_of(self, other): - return self.exclude(self.descendant_of_q(other)) + return q + + def descendant_of(self, other, inclusive=False): + return self.filter(self.descendant_of_q(other, inclusive)) + + def not_descendant_of(self, other, inclusive=False): + return self.exclude(self.descendant_of_q(other, inclusive)) def child_of_q(self, other): return self.descendant_of_q(other) & Q(depth=other.depth + 1) @@ -43,18 +48,23 @@ class PageQuerySet(QuerySet): def not_child_of(self, other): return self.exclude(self.child_of_q(other)) - def ascendant_of_q(self, other): + def ascendant_of_q(self, other, inclusive=False): paths = [ other.path[0:pos] - for pos in range(0, len(other.path), other.steplen)[1:] + for pos in range(0, len(other.path) + 1, other.steplen)[1:] ] - return Q(path__in=paths) + q = Q(path__in=paths) - def ascendant_of(self, other): - return self.filter(self.ascendant_of_q(other)) + if not inclusive: + q &= ~self.page_q(other) - def not_ascendant_of(self, other): - return self.exclude(self.ascendant_of_q(other)) + return q + + def ascendant_of(self, other, inclusive=False): + return self.filter(self.ascendant_of_q(other, inclusive)) + + def not_ascendant_of(self, other, inclusive=False): + return self.exclude(self.ascendant_of_q(other, inclusive)) def parent_of_q(self, other): return Q(path=self.model._get_parent_path_from_path(other.path)) @@ -65,14 +75,19 @@ class PageQuerySet(QuerySet): def not_parent_of(self, other): return self.exclude(self.parent_of_q(other)) - def sibling_of_q(self, other): - return Q(path__startswith=self.model._get_parent_path_from_path(other.path)) & Q(depth=other.depth) + def sibling_of_q(self, other, inclusive=False): + q = Q(path__startswith=self.model._get_parent_path_from_path(other.path)) & Q(depth=other.depth) - def sibling_of(self, other): - return self.filter(self.sibling_of_q(other)) + if not inclusive: + q &= ~self.page_q(other) - def not_sibling_of(self, other): - return self.exclude(self.sibling_of_q(other)) + return q + + def sibling_of(self, other, inclusive=False): + return self.filter(self.sibling_of_q(other, inclusive)) + + def not_sibling_of(self, other, inclusive=False): + return self.exclude(self.sibling_of_q(other, inclusive)) def type_q(self, model): content_type = ContentType.objects.get_for_model(model) From b48d0c6fa2637d2e85b3bf286efe0e42ffc94f72 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Mon, 7 Apr 2014 15:47:18 +0100 Subject: [PATCH 04/10] PageQuerySet: renamed 'ascendant' to 'ancestor' --- wagtail/wagtailcore/query.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/wagtail/wagtailcore/query.py b/wagtail/wagtailcore/query.py index 134ddbdcf9..2918db5b35 100644 --- a/wagtail/wagtailcore/query.py +++ b/wagtail/wagtailcore/query.py @@ -48,7 +48,7 @@ class PageQuerySet(QuerySet): def not_child_of(self, other): return self.exclude(self.child_of_q(other)) - def ascendant_of_q(self, other, inclusive=False): + def ancestor_of_q(self, other, inclusive=False): paths = [ other.path[0:pos] for pos in range(0, len(other.path) + 1, other.steplen)[1:] @@ -60,11 +60,11 @@ class PageQuerySet(QuerySet): return q - def ascendant_of(self, other, inclusive=False): - return self.filter(self.ascendant_of_q(other, inclusive)) + def ancestor_of(self, other, inclusive=False): + return self.filter(self.ancestor_of_q(other, inclusive)) - def not_ascendant_of(self, other, inclusive=False): - return self.exclude(self.ascendant_of_q(other, inclusive)) + def not_ancestor_of(self, other, inclusive=False): + return self.exclude(self.ancestor_of_q(other, inclusive)) def parent_of_q(self, other): return Q(path=self.model._get_parent_path_from_path(other.path)) From 0cbe15b7413de56a758fe8b1acd043656a8339bb Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Mon, 7 Apr 2014 16:08:07 +0100 Subject: [PATCH 05/10] Make PageQuerySet inherit from treebeards MP_NodeQuerySet --- wagtail/wagtailcore/query.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/wagtail/wagtailcore/query.py b/wagtail/wagtailcore/query.py index 2918db5b35..d182ec5887 100644 --- a/wagtail/wagtailcore/query.py +++ b/wagtail/wagtailcore/query.py @@ -1,9 +1,18 @@ -from django.db.models.query import QuerySet from django.db.models import Q from django.contrib.contenttypes.models import ContentType -class PageQuerySet(QuerySet): +# hack to import our patched copy of treebeard at wagtail/vendor/django-treebeard - +# based on http://stackoverflow.com/questions/17211078/how-to-temporarily-modify-sys-path-in-python +import sys +import os +treebeard_path = os.path.join(os.path.dirname(__file__), '..', 'vendor', 'django-treebeard') +sys.path.insert(0, treebeard_path) +from treebeard.mp_tree import MP_NodeQuerySet +sys.path.pop(0) + + +class PageQuerySet(MP_NodeQuerySet): """ Defines some extra query set methods that are useful for pages. """ From fe9ce7503e4371f80b0d65e95b083f497d0f79b5 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Mon, 7 Apr 2014 16:51:14 +0100 Subject: [PATCH 06/10] Add PageManager which returns PageQuerySet objects --- wagtail/wagtailcore/models.py | 56 ++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/wagtail/wagtailcore/models.py b/wagtail/wagtailcore/models.py index 9def327d61..8c6c55335d 100644 --- a/wagtail/wagtailcore/models.py +++ b/wagtail/wagtailcore/models.py @@ -129,6 +129,59 @@ def get_navigable_page_content_type_ids(): return _NAVIGABLE_PAGE_CONTENT_TYPE_IDS +class PageManager(models.Manager): + def get_query_set(self): + return PageQuerySet(self.model).order_by('path') + + def live(self): + return self.get_query_set().live() + + def not_live(self): + return self.get_query_set().not_live() + + def page(self, other): + return self.get_query_set().page(other) + + def not_page(self, other): + return self.get_query_set().not_page(other) + + def descendant_of(self, other, inclusive=False): + return self.get_query_set().descendant_of(other, inclusive) + + def not_descendant_of(self, other, inclusive=False): + return self.get_query_set().not_descendant_of(other, inclusive) + + def child_of(self, other): + return self.get_query_set().child_of(other) + + def not_child_of(self, other): + return self.get_query_set().not_child_of(other) + + def ancestor_of(self, other, inclusive=False): + return self.get_query_set().ancestor_of(other, inclusive) + + def not_ancestor_of(self, other, inclusive=False): + return self.get_query_set().not_ancestor_of(other, inclusive) + + def parent_of(self, other): + return self.get_query_set().parent_of(other) + + def not_parent_of(self, other): + return self.get_query_set().not_parent_of(other) + + def sibling_of(self, other, inclusive=False): + return self.get_query_set().sibling_of(other, inclusive) + + def not_sibling_of(self, other, inclusive=False): + return self.get_query_set().not_sibling_of(other, inclusive) + + def type(self, model): + return self.get_query_set().type(model) + + def not_type(self, model): + return self.get_query_set().not_type(model) + + class PageBase(models.base.ModelBase): """Metaclass for Page""" def __init__(cls, name, bases, dct): @@ -139,7 +192,8 @@ class PageBase(models.base.ModelBase): # don't proceed with all this page type registration stuff return - cls.query = PageQuerySet(model=cls) + # Add page manager + PageManager().contribute_to_class(cls, 'objects') if 'template' not in dct: # Define a default template path derived from the app name and model name From d101e18109c969e60bf3b4e144c85c292baecc05 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Mon, 7 Apr 2014 19:22:45 +0100 Subject: [PATCH 07/10] Added unit tests for PageQuerySet --- wagtail/wagtailcore/tests.py | 233 +++++++++++++++++++++++++++++++++++ 1 file changed, 233 insertions(+) diff --git a/wagtail/wagtailcore/tests.py b/wagtail/wagtailcore/tests.py index ce1b1ef90f..b35eda78f8 100644 --- a/wagtail/wagtailcore/tests.py +++ b/wagtail/wagtailcore/tests.py @@ -335,3 +335,236 @@ class TestPagePermission(TestCase): self.assertTrue(homepage_perms.can_move_to(root)) self.assertFalse(homepage_perms.can_move_to(unpublished_event_page)) + + +class TestPageQuerySet(TestCase): + fixtures = ['test.json'] + + def test_live(self): + pages = Page.objects.live() + + # All pages must be live + for page in pages: + self.assertTrue(page.live) + + def test_not_live(self): + pages = Page.objects.not_live() + + # All pages must not be live + for page in pages: + self.assertFalse(page.live) + + def test_page(self): + homepage = Page.objects.get(url_path='/home/') + pages = Page.objects.page(homepage) + + # Should only select the homepage + self.assertEqual(pages.count(), 1) + self.assertEqual(pages.first(), homepage) + + def test_not_page(self): + homepage = Page.objects.get(url_path='/home/') + pages = Page.objects.not_page(homepage) + + # Should select everything except for the homepage + self.assertEqual(pages.count(), Page.objects.all().count() - 1) + for page in pages: + self.assertNotEqual(page, homepage) + + def test_descendant_of(self): + events_index = Page.objects.get(url_path='/home/events/') + pages = Page.objects.descendant_of(events_index) + + # Check that all pages descend from events index + for page in pages: + self.assertTrue(page.get_ancestors().filter(id=events_index.id).exists()) + + def test_descendant_of_inclusive(self): + events_index = Page.objects.get(url_path='/home/events/') + pages = Page.objects.descendant_of(events_index, inclusive=True) + + # Check that all pages descend from events index, includes event index + for page in pages: + self.assertTrue(page == events_index or page.get_ancestors().filter(id=events_index.id).exists()) + + # Check that event index was included + self.assertTrue(pages.filter(id=events_index.id).exists()) + + def test_not_descendant_of(self): + homepage = Page.objects.get(url_path='/home/') + events_index = Page.objects.get(url_path='/home/events/') + pages = Page.objects.descendant_of(homepage).not_descendant_of(events_index) + + # Check that all pages descend from homepage but not events index + for page in pages: + self.assertTrue(page.get_ancestors().filter(id=homepage.id).exists()) + self.assertFalse(page.get_ancestors().filter(id=events_index.id).exists()) + + # As this is not inclusive, events index should be in the results + self.assertTrue(pages.filter(id=events_index.id).exists()) + + def test_not_descendant_of_inclusive(self): + homepage = Page.objects.get(url_path='/home/') + events_index = Page.objects.get(url_path='/home/events/') + pages = Page.objects.descendant_of(homepage).not_descendant_of(events_index, inclusive=True) + + # Check that all pages descend from homepage but not events index + for page in pages: + self.assertTrue(page.get_ancestors().filter(id=homepage.id).exists()) + self.assertFalse(page.get_ancestors().filter(id=events_index.id).exists()) + + # Events index should be excluded from results + self.assertNotEqual(page, events_index) + + def test_child_of(self): + homepage = Page.objects.get(url_path='/home/') + pages = Page.objects.child_of(homepage) + + # Check that all pages are children of homepage + for page in pages: + self.assertEqual(page.get_parent(), homepage) + + def test_not_child_of(self): + events_index = Page.objects.get(url_path='/home/events/') + pages = Page.objects.not_child_of(events_index) + + # Check that all pages are not children of events_index + for page in pages: + self.assertNotEqual(page.get_parent(), events_index) + + def test_ancestor_of(self): + root_page = Page.objects.get(id=1) + homepage = Page.objects.get(url_path='/home/') + events_index = Page.objects.get(url_path='/home/events/') + pages = Page.objects.ancestor_of(events_index) + + self.assertEqual(pages.count(), 2) + self.assertEqual(pages[0], root_page) + self.assertEqual(pages[1], homepage) + + def test_ancestor_of_inclusive(self): + root_page = Page.objects.get(id=1) + homepage = Page.objects.get(url_path='/home/') + events_index = Page.objects.get(url_path='/home/events/') + pages = Page.objects.ancestor_of(events_index, inclusive=True) + + self.assertEqual(pages.count(), 3) + self.assertEqual(pages[0], root_page) + self.assertEqual(pages[1], homepage) + self.assertEqual(pages[2], events_index) + + def test_not_ancestor_of(self): + root_page = Page.objects.get(id=1) + homepage = Page.objects.get(url_path='/home/') + events_index = Page.objects.get(url_path='/home/events/') + pages = Page.objects.not_ancestor_of(events_index) + + # Test that none of the ancestors are in pages + for page in pages: + self.assertNotEqual(page, root_page) + self.assertNotEqual(page, homepage) + + # Test that events index is in pages + self.assertTrue(pages.filter(id=events_index.id).exists()) + + def test_not_ancestor_of_inclusive(self): + root_page = Page.objects.get(id=1) + homepage = Page.objects.get(url_path='/home/') + events_index = Page.objects.get(url_path='/home/events/') + pages = Page.objects.not_ancestor_of(events_index, inclusive=True) + + # Test that none of the ancestors or the events_index are in pages + for page in pages: + self.assertNotEqual(page, root_page) + self.assertNotEqual(page, homepage) + self.assertNotEqual(page, events_index) + + def test_parent_of(self): + homepage = Page.objects.get(url_path='/home/') + events_index = Page.objects.get(url_path='/home/events/') + pages = Page.objects.parent_of(events_index) + + # Pages must only contain homepage + self.assertEqual(pages.count(), 1) + self.assertEqual(pages[0], homepage) + + def test_not_parent_of(self): + homepage = Page.objects.get(url_path='/home/') + events_index = Page.objects.get(url_path='/home/events/') + pages = Page.objects.not_parent_of(events_index) + + # Pages must not contain homepage + for page in pages: + self.assertNotEqual(page, homepage) + + # Test that events index is in pages + self.assertTrue(pages.filter(id=events_index.id).exists()) + + def test_sibling_of(self): + events_index = Page.objects.get(url_path='/home/events/') + event = Page.objects.get(url_path='/home/events/christmas/') + pages = Page.objects.sibling_of(event) + + # Check that all pages are children of events_index + for page in pages: + self.assertEqual(page.get_parent(), events_index) + + # Check that the event is not included + self.assertFalse(pages.filter(id=event.id).exists()) + + def test_sibling_of_inclusive(self): + events_index = Page.objects.get(url_path='/home/events/') + event = Page.objects.get(url_path='/home/events/christmas/') + pages = Page.objects.sibling_of(event, inclusive=True) + + # Check that all pages are children of events_index + for page in pages: + self.assertEqual(page.get_parent(), events_index) + + # Check that the event is included + self.assertTrue(pages.filter(id=event.id).exists()) + + def test_not_sibling_of(self): + events_index = Page.objects.get(url_path='/home/events/') + event = Page.objects.get(url_path='/home/events/christmas/') + pages = Page.objects.not_sibling_of(event) + + # Check that all pages are not children of events_index + for page in pages: + if page != event: + self.assertNotEqual(page.get_parent(), events_index) + + # Check that the event is included + self.assertTrue(pages.filter(id=event.id).exists()) + + # Test that events index is in pages + self.assertTrue(pages.filter(id=events_index.id).exists()) + + def test_not_sibling_of_inclusive(self): + events_index = Page.objects.get(url_path='/home/events/') + event = Page.objects.get(url_path='/home/events/christmas/') + pages = Page.objects.not_sibling_of(event, inclusive=True) + + # Check that all pages are not children of events_index + for page in pages: + self.assertNotEqual(page.get_parent(), events_index) + + # Check that the event is not included + self.assertFalse(pages.filter(id=event.id).exists()) + + # Test that events index is in pages + self.assertTrue(pages.filter(id=events_index.id).exists()) + + def test_type(self): + pages = Page.objects.type(EventPage) + + # Check that all objects are EventPages + for page in pages: + self.assertIsInstance(page.specific, EventPage) + + def test_not_type(self): + pages = Page.objects.not_type(EventPage) + + # Check that no objects are EventPages + for page in pages: + self.assertNotIsInstance(page.specific, EventPage) From d85f4c3eb53bb76dab24e19385193fe04ab09864 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Mon, 7 Apr 2014 17:22:47 +0100 Subject: [PATCH 08/10] Added changelog entry --- CHANGELOG.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index ddbca7e398..1472f8bdf1 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -5,6 +5,7 @@ Changelog ~~~~~~~~~~~~~~~~ * Added toolbar to allow logged-in users to add and edit pages from the site front-end * Support for alternative image processing backends such as Wand, via the WAGTAILIMAGES_BACKENDS setting + * Added custom Query set for Pages with some handy methods for querying pages * Editor's guide documentation * Editor interface now outputs form media CSS / JS, to support custom widgets with assets * Migrations and user management now correctly handle custom AUTH_USER_MODEL settings From 6c0d543423d651d55069ccffbe70d6f83c82b42d Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Mon, 7 Apr 2014 19:41:59 +0100 Subject: [PATCH 09/10] Tweaks to PageQuerySet.not_descendant_of tests --- wagtail/wagtailcore/tests.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/wagtail/wagtailcore/tests.py b/wagtail/wagtailcore/tests.py index b35eda78f8..fb08392663 100644 --- a/wagtail/wagtailcore/tests.py +++ b/wagtail/wagtailcore/tests.py @@ -393,11 +393,10 @@ class TestPageQuerySet(TestCase): def test_not_descendant_of(self): homepage = Page.objects.get(url_path='/home/') events_index = Page.objects.get(url_path='/home/events/') - pages = Page.objects.descendant_of(homepage).not_descendant_of(events_index) + pages = Page.objects.not_descendant_of(events_index) - # Check that all pages descend from homepage but not events index + # Check that no pages descend from events_index for page in pages: - self.assertTrue(page.get_ancestors().filter(id=homepage.id).exists()) self.assertFalse(page.get_ancestors().filter(id=events_index.id).exists()) # As this is not inclusive, events index should be in the results @@ -406,15 +405,14 @@ class TestPageQuerySet(TestCase): def test_not_descendant_of_inclusive(self): homepage = Page.objects.get(url_path='/home/') events_index = Page.objects.get(url_path='/home/events/') - pages = Page.objects.descendant_of(homepage).not_descendant_of(events_index, inclusive=True) + pages = Page.objects.not_descendant_of(events_index, inclusive=True) # Check that all pages descend from homepage but not events index for page in pages: - self.assertTrue(page.get_ancestors().filter(id=homepage.id).exists()) self.assertFalse(page.get_ancestors().filter(id=events_index.id).exists()) - # Events index should be excluded from results - self.assertNotEqual(page, events_index) + # As this is inclusive, events index should not be in the results + self.assertFalse(pages.filter(id=events_index.id).exists()) def test_child_of(self): homepage = Page.objects.get(url_path='/home/') From e44dfee94ca64a4ccc746682662d1027011d2983 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Tue, 8 Apr 2014 12:48:42 +0100 Subject: [PATCH 10/10] PageQuerySet live/type tests now check that the methods return certian objects --- wagtail/wagtailcore/tests.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/wagtail/wagtailcore/tests.py b/wagtail/wagtailcore/tests.py index fb08392663..b352dbc8f0 100644 --- a/wagtail/wagtailcore/tests.py +++ b/wagtail/wagtailcore/tests.py @@ -347,6 +347,10 @@ class TestPageQuerySet(TestCase): for page in pages: self.assertTrue(page.live) + # Check that the homepage is in the results + homepage = Page.objects.get(url_path='/home/') + self.assertTrue(pages.filter(id=homepage.id).exists()) + def test_not_live(self): pages = Page.objects.not_live() @@ -354,6 +358,10 @@ class TestPageQuerySet(TestCase): for page in pages: self.assertFalse(page.live) + # Check that "someone elses event" is in the results + event = Page.objects.get(url_path='/home/events/someone-elses-event/') + self.assertTrue(pages.filter(id=event.id).exists()) + def test_page(self): homepage = Page.objects.get(url_path='/home/') pages = Page.objects.page(homepage) @@ -560,9 +568,17 @@ class TestPageQuerySet(TestCase): for page in pages: self.assertIsInstance(page.specific, EventPage) + # Check that "someone elses event" is in the results + event = Page.objects.get(url_path='/home/events/someone-elses-event/') + self.assertTrue(pages.filter(id=event.id).exists()) + def test_not_type(self): pages = Page.objects.not_type(EventPage) # Check that no objects are EventPages for page in pages: self.assertNotIsInstance(page.specific, EventPage) + + # Check that the homepage is in the results + homepage = Page.objects.get(url_path='/home/') + self.assertTrue(pages.filter(id=homepage.id).exists())