0
0
mirror of https://github.com/wagtail/wagtail.git synced 2024-11-29 17:36:49 +01:00

Stop replace_text from replacing multiple times on MTI subclasses.

Iterating over get_page_models means that these will be visited once
per superclass. To avoid this, we filter the page list to those exactly
matching the page class. This is done via a new `exact_type` method
on `PageQuerySet`.
This commit is contained in:
Matt Westcott 2015-11-30 20:27:10 +00:00
parent 1bb74ee4d0
commit b1c75644f6
4 changed files with 76 additions and 1 deletions

View File

@ -202,6 +202,24 @@ Reference
.. automethod:: not_type
.. automethod:: exact_type
Example:
.. code-block:: python
# Find all pages that are of the exact type EventPage
event_pages = Page.objects.exact_type(EventPage)
.. automethod:: not_exact_type
Example:
.. code-block:: python
# Find all pages that are not of the exact type EventPage (but may be a subclass)
non_event_pages = Page.objects.not_exact_type(EventPage)
.. automethod:: unpublish
Example:

View File

@ -32,7 +32,10 @@ class Command(BaseCommand):
child_relation_names = [rel.get_accessor_name() for rel in get_all_child_relations(page_class)]
for page in page_class.objects.all():
# Find all pages of this exact type; exclude subclasses, as they will
# appear in the get_page_models() list in their own right, and this
# ensures that replacement happens only once
for page in page_class.objects.exact_type(page_class):
replace_in_model(page, from_text, to_text)
for child_rel in child_relation_names:
for child in getattr(page, child_rel).all():

View File

@ -191,6 +191,23 @@ class PageQuerySet(SearchableQuerySetMixin, TreeQuerySet):
"""
return self.exclude(self.type_q(model))
def exact_type_q(self, klass):
return Q(content_type=ContentType.objects.get_for_model(klass))
def exact_type(self, model):
"""
This filters the QuerySet to only contain pages that are an instance of the specified model
(matching the model exactly, not subclasses).
"""
return self.filter(self.exact_type_q(model))
def not_exact_type(self, model):
"""
This filters the QuerySet to not contain any pages which are an instance of the specified model
(matching the model exactly, not subclasses).
"""
return self.exclude(self.exact_type_q(model))
def public_q(self):
from wagtail.wagtailcore.models import PageViewRestriction

View File

@ -294,6 +294,11 @@ class TestPageQuerySet(TestCase):
event = Page.objects.get(url_path='/home/events/someone-elses-event/')
self.assertTrue(pages.filter(id=event.id).exists())
# Check that "Saint Patrick" (an instance of SingleEventPage, a subclass of EventPage)
# is in the results
event = Page.objects.get(url_path='/home/events/saint-patrick/')
self.assertTrue(pages.filter(id=event.id).exists())
def test_type_includes_subclasses(self):
from wagtail.wagtailforms.models import AbstractEmailForm
pages = Page.objects.type(AbstractEmailForm)
@ -317,6 +322,38 @@ class TestPageQuerySet(TestCase):
homepage = Page.objects.get(url_path='/home/')
self.assertTrue(pages.filter(id=homepage.id).exists())
def test_exact_type(self):
pages = Page.objects.exact_type(EventPage)
# Check that all objects are EventPages (and not a subclass)
for page in pages:
self.assertEqual(type(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())
# Check that "Saint Patrick" (an instance of SingleEventPage, a subclass of EventPage)
# is NOT in the results
event = Page.objects.get(url_path='/home/events/saint-patrick/')
self.assertFalse(pages.filter(id=event.id).exists())
def test_not_exact_type(self):
pages = Page.objects.not_exact_type(EventPage)
# Check that no objects are EventPages
for page in pages:
self.assertNotEqual(type(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())
# Check that "Saint Patrick" (an instance of SingleEventPage, a subclass of EventPage)
# is in the results
event = Page.objects.get(url_path='/home/events/saint-patrick/')
self.assertTrue(pages.filter(id=event.id).exists())
def test_public(self):
events_index = Page.objects.get(url_path='/home/events/')
event = Page.objects.get(url_path='/home/events/christmas/')