`_
+
You no longer need ``LOGIN_URL`` and ``LOGIN_REDIRECT_URL`` to point to Wagtail admin.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/wagtail/contrib/wagtailfrontendcache/signal_handlers.py b/wagtail/contrib/wagtailfrontendcache/signal_handlers.py
index fe673825f..3e5def1c1 100644
--- a/wagtail/contrib/wagtailfrontendcache/signal_handlers.py
+++ b/wagtail/contrib/wagtailfrontendcache/signal_handlers.py
@@ -1,4 +1,4 @@
-from django.db import models
+from django.apps import apps
from wagtail.wagtailcore.signals import page_published, page_unpublished
@@ -15,8 +15,8 @@ def page_unpublished_signal_handler(instance, **kwargs):
def register_signal_handlers():
# Get list of models that are page types
- Page = models.get_model('wagtailcore', 'Page')
- indexed_models = [model for model in models.get_models() if issubclass(model, Page)]
+ Page = apps.get_model('wagtailcore', 'Page')
+ indexed_models = [model for model in apps.get_models() if issubclass(model, Page)]
# Loop through list and register signal handlers for each one
for model in indexed_models:
diff --git a/wagtail/contrib/wagtailroutablepage/tests.py b/wagtail/contrib/wagtailroutablepage/tests.py
index 1aa8f53d1..2226b5cb5 100644
--- a/wagtail/contrib/wagtailroutablepage/tests.py
+++ b/wagtail/contrib/wagtailroutablepage/tests.py
@@ -1,7 +1,7 @@
from django.test import TestCase, RequestFactory
from wagtail.wagtailcore.models import Page, Site
-from wagtail.tests.models import RoutablePageTest, routable_page_external_view
+from wagtail.tests.routablepage.models import RoutablePageTest, routable_page_external_view
from wagtail.contrib.wagtailroutablepage.templatetags.wagtailroutablepage_tags import routablepageurl
diff --git a/wagtail/contrib/wagtailsitemaps/tests.py b/wagtail/contrib/wagtailsitemaps/tests.py
index a2d0498d7..5fba8f57e 100644
--- a/wagtail/contrib/wagtailsitemaps/tests.py
+++ b/wagtail/contrib/wagtailsitemaps/tests.py
@@ -2,7 +2,7 @@ from django.test import TestCase
from django.core.cache import cache
from wagtail.wagtailcore.models import Page, PageViewRestriction, Site
-from wagtail.tests.models import SimplePage, EventIndex
+from wagtail.tests.testapp.models import SimplePage, EventIndex
from .sitemap_generator import Sitemap
diff --git a/wagtail/project_template/project_name/settings/production.py b/wagtail/project_template/project_name/settings/production.py
index e9e9e1971..bf20125a9 100644
--- a/wagtail/project_template/project_name/settings/production.py
+++ b/wagtail/project_template/project_name/settings/production.py
@@ -13,19 +13,6 @@ TEMPLATE_DEBUG = False
COMPRESS_OFFLINE = True
-# Send notification emails as a background task using Celery,
-# to prevent this from blocking web server threads
-# (requires the django-celery package):
-# http://celery.readthedocs.org/en/latest/configuration.html
-
-# import djcelery
-#
-# djcelery.setup_loader()
-#
-# CELERY_SEND_TASK_ERROR_EMAILS = True
-# BROKER_URL = 'redis://'
-
-
# Use Redis as the cache backend for extra performance
# (requires the django-redis-cache package):
# http://wagtail.readthedocs.org/en/latest/howto/performance.html#cache
diff --git a/wagtail/project_template/requirements.txt b/wagtail/project_template/requirements.txt
index cccb37a38..a2ad30e9b 100644
--- a/wagtail/project_template/requirements.txt
+++ b/wagtail/project_template/requirements.txt
@@ -8,4 +8,3 @@ wagtail==1.0b1
# Recommended components to improve performance in production:
# django-redis==3.8.2
-# django-celery==3.1.10
diff --git a/wagtail/tests/migrations/__init__.py b/wagtail/tests/customuser/__init__.py
similarity index 100%
rename from wagtail/tests/migrations/__init__.py
rename to wagtail/tests/customuser/__init__.py
diff --git a/wagtail/tests/migrations/0001_initial.py b/wagtail/tests/customuser/migrations/0001_initial.py
similarity index 100%
rename from wagtail/tests/migrations/0001_initial.py
rename to wagtail/tests/customuser/migrations/0001_initial.py
diff --git a/wagtail/tests/customuser/migrations/0002_auto_20150330_0653.py b/wagtail/tests/customuser/migrations/0002_auto_20150330_0653.py
new file mode 100644
index 000000000..30be9eec6
--- /dev/null
+++ b/wagtail/tests/customuser/migrations/0002_auto_20150330_0653.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('customuser', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='customuser',
+ name='groups',
+ field=models.ManyToManyField(to='auth.Group', verbose_name='groups', help_text='The groups this user belongs to. A user will get all permissions granted to each of his/her group.', related_name='user_set', blank=True, related_query_name='user'),
+ preserve_default=True,
+ ),
+ migrations.AlterField(
+ model_name='customuser',
+ name='user_permissions',
+ field=models.ManyToManyField(to='auth.Permission', verbose_name='user permissions', help_text='Specific permissions for this user.', related_name='user_set', blank=True, related_query_name='user'),
+ preserve_default=True,
+ ),
+ ]
diff --git a/wagtail/tests/customuser/migrations/__init__.py b/wagtail/tests/customuser/migrations/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/wagtail/tests/customuser/models.py b/wagtail/tests/customuser/models.py
new file mode 100644
index 000000000..cd09fa6e3
--- /dev/null
+++ b/wagtail/tests/customuser/models.py
@@ -0,0 +1,47 @@
+from django.db import models
+
+from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager
+
+
+class CustomUserManager(BaseUserManager):
+ def _create_user(self, username, email, password,
+ is_staff, is_superuser, **extra_fields):
+ """
+ Creates and saves a User with the given username, email and password.
+ """
+ if not username:
+ raise ValueError('The given username must be set')
+ email = self.normalize_email(email)
+ user = self.model(username=username, email=email,
+ is_staff=is_staff, is_active=True,
+ is_superuser=is_superuser, **extra_fields)
+ user.set_password(password)
+ user.save(using=self._db)
+ return user
+
+ def create_user(self, username, email=None, password=None, **extra_fields):
+ return self._create_user(username, email, password, False, False,
+ **extra_fields)
+
+ def create_superuser(self, username, email, password, **extra_fields):
+ return self._create_user(username, email, password, True, True,
+ **extra_fields)
+
+
+class CustomUser(AbstractBaseUser, PermissionsMixin):
+ username = models.CharField(max_length=100, unique=True)
+ email = models.EmailField(max_length=255, blank=True)
+ is_staff = models.BooleanField(default=True)
+ is_active = models.BooleanField(default=True)
+ first_name = models.CharField(max_length=50, blank=True)
+ last_name = models.CharField(max_length=50, blank=True)
+
+ USERNAME_FIELD = 'username'
+
+ objects = CustomUserManager()
+
+ def get_full_name(self):
+ return self.first_name + ' ' + self.last_name
+
+ def get_short_name(self):
+ return self.first_name
diff --git a/wagtail/tests/demosite/__init__.py b/wagtail/tests/demosite/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/wagtail/tests/demosite/fixtures/demosite.json b/wagtail/tests/demosite/fixtures/demosite.json
new file mode 100644
index 000000000..4c730e064
--- /dev/null
+++ b/wagtail/tests/demosite/fixtures/demosite.json
@@ -0,0 +1,1150 @@
+[
+{
+ "pk": 1,
+ "model": "wagtailcore.page",
+ "fields": {
+ "title": "Root",
+ "numchild": 1,
+ "show_in_menus": false,
+ "live": true,
+ "seo_title": "",
+ "depth": 1,
+ "search_description": "",
+ "content_type": [
+ "wagtailcore",
+ "page"
+ ],
+ "has_unpublished_changes": false,
+ "owner": null,
+ "path": "0001",
+ "url_path": "/",
+ "slug": "root"
+ }
+},
+{
+ "pk": 2,
+ "model": "wagtailcore.page",
+ "fields": {
+ "title": "Home page",
+ "numchild": 5,
+ "show_in_menus": true,
+ "live": true,
+ "seo_title": "",
+ "depth": 2,
+ "search_description": "",
+ "content_type": [
+ "demosite",
+ "homepage"
+ ],
+ "has_unpublished_changes": false,
+ "owner": null,
+ "path": "00010002",
+ "url_path": "/home-page/",
+ "slug": "home-page"
+ }
+},
+{
+ "pk": 4,
+ "model": "wagtailcore.page",
+ "fields": {
+ "title": "Events index",
+ "numchild": 2,
+ "show_in_menus": true,
+ "live": true,
+ "seo_title": "",
+ "depth": 3,
+ "search_description": "",
+ "content_type": [
+ "demosite",
+ "eventindexpage"
+ ],
+ "has_unpublished_changes": false,
+ "owner": null,
+ "path": "000100020001",
+ "url_path": "/home-page/events-index/",
+ "slug": "events-index"
+ }
+},
+{
+ "pk": 5,
+ "model": "wagtailcore.page",
+ "fields": {
+ "title": "Blog index",
+ "numchild": 3,
+ "show_in_menus": true,
+ "live": true,
+ "seo_title": "",
+ "depth": 3,
+ "search_description": "",
+ "content_type": [
+ "demosite",
+ "blogindexpage"
+ ],
+ "has_unpublished_changes": false,
+ "owner": null,
+ "path": "000100020002",
+ "url_path": "/home-page/blog-index/",
+ "slug": "blog-index"
+ }
+},
+{
+ "pk": 6,
+ "model": "wagtailcore.page",
+ "fields": {
+ "title": "Standard index",
+ "numchild": 4,
+ "show_in_menus": true,
+ "live": true,
+ "seo_title": "",
+ "depth": 3,
+ "search_description": "",
+ "content_type": [
+ "demosite",
+ "standardindexpage"
+ ],
+ "has_unpublished_changes": false,
+ "owner": null,
+ "path": "000100020003",
+ "url_path": "/home-page/standard-index/",
+ "slug": "standard-index"
+ }
+},
+{
+ "pk": 8,
+ "model": "wagtailcore.page",
+ "fields": {
+ "title": "Event 1",
+ "numchild": 0,
+ "show_in_menus": false,
+ "live": true,
+ "seo_title": "",
+ "depth": 4,
+ "search_description": "At first glance, the wagtails appear to be divided into a yellow-bellied group and a white-bellied one",
+ "content_type": [
+ "demosite",
+ "eventpage"
+ ],
+ "has_unpublished_changes": false,
+ "owner": null,
+ "path": "0001000200010001",
+ "url_path": "/home-page/events-index/event-1/",
+ "slug": "event-1"
+ }
+},
+{
+ "pk": 9,
+ "model": "wagtailcore.page",
+ "fields": {
+ "title": "Event 2",
+ "numchild": 0,
+ "show_in_menus": false,
+ "live": true,
+ "seo_title": "",
+ "depth": 4,
+ "search_description": "Three species are poly- or paraphyletic in the present taxonomical arrangement and either subspecies need to be reassigned and/or species split up. The Blue-headed Wagtail (AKA Yellow Wagtail and many other names), especially, has always been a taxonomical nightmare with over a dozen currently accepted subspecies and many more invalid ones. The two remaining \"monochrome\" species, Mekong and African Pied Wagtail may be closely related, or a most striking example of convergent evolution.",
+ "content_type": [
+ "demosite",
+ "eventpage"
+ ],
+ "has_unpublished_changes": false,
+ "owner": null,
+ "path": "0001000200010002",
+ "url_path": "/home-page/events-index/event-2/",
+ "slug": "event-2"
+ }
+},
+{
+ "pk": 10,
+ "model": "wagtailcore.page",
+ "fields": {
+ "title": "Standard page 1",
+ "numchild": 0,
+ "show_in_menus": true,
+ "live": true,
+ "seo_title": "",
+ "depth": 4,
+ "search_description": "Wagtails are slender, often colourful, ground-feeding insectivores of open country in the Old World. They are ground nesters.",
+ "content_type": [
+ "demosite",
+ "standardpage"
+ ],
+ "has_unpublished_changes": false,
+ "owner": null,
+ "path": "0001000200030001",
+ "url_path": "/home-page/standard-index/standard-page-1/",
+ "slug": "standard-page-1"
+ }
+},
+{
+ "pk": 12,
+ "model": "wagtailcore.page",
+ "fields": {
+ "title": "Contact page",
+ "numchild": 0,
+ "show_in_menus": true,
+ "live": true,
+ "seo_title": "",
+ "depth": 3,
+ "search_description": "The origin of the genus appears to be in the general area of Eastern Siberia/Mongolia. Wagtails spread rapidly across Eurasia and dispersed to Africa in the Zanclean...",
+ "content_type": [
+ "demosite",
+ "contactpage"
+ ],
+ "has_unpublished_changes": false,
+ "owner": null,
+ "path": "000100020005",
+ "url_path": "/home-page/contact-page/",
+ "slug": "contact-page"
+ }
+},
+{
+ "pk": 13,
+ "model": "wagtailcore.page",
+ "fields": {
+ "title": "James Joyce",
+ "numchild": 0,
+ "show_in_menus": true,
+ "live": true,
+ "seo_title": "",
+ "depth": 4,
+ "search_description": "The origin of the genus appears to be in the general area of Eastern Siberia/Mongolia. Wagtails spread rapidly across Eurasia and dispersed to Africa",
+ "content_type": [
+ "demosite",
+ "personpage"
+ ],
+ "has_unpublished_changes": false,
+ "owner": null,
+ "path": "0001000200040001",
+ "url_path": "/home-page/people/james-joyce/",
+ "slug": "james-joyce"
+ }
+},
+{
+ "pk": 14,
+ "model": "wagtailcore.page",
+ "fields": {
+ "title": "David Mitchell",
+ "numchild": 0,
+ "show_in_menus": true,
+ "live": true,
+ "seo_title": "",
+ "depth": 4,
+ "search_description": "Recent studies have suggested instead that it is a signal of vigilance that may aid to deter potential predators.",
+ "content_type": [
+ "demosite",
+ "personpage"
+ ],
+ "has_unpublished_changes": false,
+ "owner": null,
+ "path": "0001000200040002",
+ "url_path": "/home-page/people/david-mitchell/",
+ "slug": "david-mitchell"
+ }
+},
+{
+ "pk": 15,
+ "model": "wagtailcore.page",
+ "fields": {
+ "title": "Standard page 2",
+ "numchild": 0,
+ "show_in_menus": true,
+ "live": true,
+ "seo_title": "",
+ "depth": 4,
+ "search_description": "The remaining five species are highly variable morphologically and their relationships with each other and with the two clades have not yet been satisfactorily explained.",
+ "content_type": [
+ "demosite",
+ "standardpage"
+ ],
+ "has_unpublished_changes": false,
+ "owner": null,
+ "path": "0001000200030002",
+ "url_path": "/home-page/standard-index/standard-page-2/",
+ "slug": "standard-page-2"
+ }
+},
+{
+ "pk": 16,
+ "model": "wagtailcore.page",
+ "fields": {
+ "title": "Blog post",
+ "numchild": 0,
+ "show_in_menus": false,
+ "live": true,
+ "seo_title": "",
+ "depth": 4,
+ "search_description": "The origin of the genus appears to be in the general area of Eastern Siberia/Mongolia. Wagtails spread rapidly across Eurasia and dispersed to Africa in the Zanclean (Early Pliocene) where the sub-Saharan lineage was later isolated. The African Pied Wagtail (and possibly the Mekong Wagtail) diverged prior to the massive radiation of the white-bellied black-throated and most yellow-bellied forms, all of which took place during the late Piacenzian (early Late Pliocene), c. 3 mya.",
+ "content_type": [
+ "demosite",
+ "blogentrypage"
+ ],
+ "has_unpublished_changes": false,
+ "owner": null,
+ "path": "0001000200020001",
+ "url_path": "/home-page/blog-index/blog-post/",
+ "slug": "blog-post"
+ }
+},
+{
+ "pk": 17,
+ "model": "wagtailcore.page",
+ "fields": {
+ "title": "Photo credits",
+ "numchild": 0,
+ "show_in_menus": false,
+ "live": true,
+ "seo_title": "",
+ "depth": 4,
+ "search_description": "",
+ "content_type": [
+ "demosite",
+ "standardpage"
+ ],
+ "has_unpublished_changes": false,
+ "owner": null,
+ "path": "0001000200030007",
+ "url_path": "/home-page/standard-index/photo-credits/",
+ "slug": "photo-credits"
+ }
+},
+{
+ "pk": 18,
+ "model": "wagtailcore.page",
+ "fields": {
+ "title": "Blog post again",
+ "numchild": 0,
+ "show_in_menus": false,
+ "live": true,
+ "seo_title": "",
+ "depth": 4,
+ "search_description": "Wagtails are slender, often colourful, ground-feeding insectivores of open country in the Old World. They are ground nesters, laying up to six speckled eggs at a time. Among their most conspicuous behaviours is a near constant tail wagging, a trait that has given the birds their common name. In spite of the ubiquity of the behaviour and observations of it, the reasons for it are poorly understood. It has been suggested that it may flush up prey, or that it may signal submissiveness to other wagtails. Recent studies have suggested instead that it is a signal of vigilance that may aid to deter potential predators.",
+ "content_type": [
+ "demosite",
+ "blogentrypage"
+ ],
+ "has_unpublished_changes": false,
+ "owner": null,
+ "path": "0001000200020002",
+ "url_path": "/home-page/blog-index/blog-post-again/",
+ "slug": "blog-post-again"
+ }
+},
+{
+ "pk": 19,
+ "model": "wagtailcore.page",
+ "fields": {
+ "title": "Another blog post",
+ "numchild": 0,
+ "show_in_menus": false,
+ "live": true,
+ "seo_title": "",
+ "depth": 4,
+ "search_description": "Three species are poly- or paraphyletic in the present taxonomical arrangement and either subspecies need to be reassigned and/or species split up. The Blue-headed Wagtail (AKA Yellow Wagtail and many other names), especially, has always been a taxonomical nightmare with over a dozen currently accepted subspecies and many more invalid ones. The two remaining \"monochrome\" species, Mekong and African Pied Wagtail may be closely related, or a most striking example of convergent evolution.",
+ "content_type": [
+ "demosite",
+ "blogentrypage"
+ ],
+ "has_unpublished_changes": false,
+ "owner": null,
+ "path": "0001000200020003",
+ "url_path": "/home-page/blog-index/another-blog-post/",
+ "slug": "another-blog-post"
+ }
+},
+{
+ "pk": 20,
+ "model": "wagtailcore.page",
+ "fields": {
+ "title": "People",
+ "numchild": 2,
+ "show_in_menus": true,
+ "live": true,
+ "seo_title": "",
+ "depth": 3,
+ "search_description": "",
+ "content_type": [
+ "demosite",
+ "standardindexpage"
+ ],
+ "has_unpublished_changes": false,
+ "owner": null,
+ "path": "000100020004",
+ "url_path": "/home-page/people/",
+ "slug": "people"
+ }
+},
+{
+ "pk": 21,
+ "model": "wagtailcore.page",
+ "fields": {
+ "title": "A deeper menu level",
+ "numchild": 2,
+ "show_in_menus": true,
+ "live": true,
+ "seo_title": "",
+ "depth": 4,
+ "search_description": "",
+ "content_type": [
+ "demosite",
+ "standardindexpage"
+ ],
+ "has_unpublished_changes": false,
+ "owner": null,
+ "path": "0001000200030008",
+ "url_path": "/home-page/standard-index/a-deeper-menu-level/",
+ "slug": "a-deeper-menu-level"
+ }
+},
+{
+ "pk": 22,
+ "model": "wagtailcore.page",
+ "fields": {
+ "title": "A grandchild page",
+ "numchild": 0,
+ "show_in_menus": true,
+ "live": true,
+ "seo_title": "",
+ "depth": 5,
+ "search_description": "The origin of the genus appears to be in the general area of Eastern Siberia/Mongolia. Wagtails spread rapidly across Eurasia and dispersed to Africa in the Zanclean (Early Pliocene) where the sub-Saharan lineage was later isolated. The African Pied Wagtail (and possibly the Mekong Wagtail) diverged prior to the massive radiation of the white-bellied black-throated and most yellow-bellied forms, all of which took place during the late Piacenzian (early Late Pliocene), c. 3 mya.",
+ "content_type": [
+ "demosite",
+ "standardpage"
+ ],
+ "has_unpublished_changes": false,
+ "owner": null,
+ "path": "00010002000300080001",
+ "url_path": "/home-page/standard-index/a-deeper-menu-level/a-grandchild-page/",
+ "slug": "a-grandchild-page"
+ }
+},
+{
+ "pk": 23,
+ "model": "wagtailcore.page",
+ "fields": {
+ "title": "Another grandchild page",
+ "numchild": 0,
+ "show_in_menus": true,
+ "live": true,
+ "seo_title": "",
+ "depth": 5,
+ "search_description": "The origin of the genus appears to be in the general area of Eastern Siberia/Mongolia. Wagtails spread rapidly across Eurasia and dispersed to Africa in the Zanclean (Early Pliocene) where the sub-Saharan lineage was later isolated. The African Pied Wagtail (and possibly the Mekong Wagtail) diverged prior to the massive radiation of the white-bellied black-throated and most yellow-bellied forms, all of which took place during the late Piacenzian (early Late Pliocene), c. 3 mya.",
+ "content_type": [
+ "demosite",
+ "standardpage"
+ ],
+ "has_unpublished_changes": false,
+ "owner": null,
+ "path": "00010002000300080002",
+ "url_path": "/home-page/standard-index/a-deeper-menu-level/another-grandchild-page/",
+ "slug": "another-grandchild-page"
+ }
+},
+{
+ "pk": 4,
+ "model": "wagtailimages.image",
+ "fields": {
+ "title": "Wagtail by mark Harkin",
+ "created_at": "2014-02-06T10:14:47.173Z",
+ "height": 427,
+ "width": 640,
+ "file": "original_images/wagtail_by_markyharky.jpg",
+ "uploaded_by_user": null
+ }
+},
+{
+ "pk": 5,
+ "model": "wagtailimages.image",
+ "fields": {
+ "title": "James Joyce",
+ "created_at": "2014-02-06T10:37:10.518Z",
+ "height": 392,
+ "width": 500,
+ "file": "original_images/James_Joyce_in_1915.jpg",
+ "uploaded_by_user": null
+ }
+},
+{
+ "pk": 6,
+ "model": "wagtailimages.image",
+ "fields": {
+ "title": "David Mitchell",
+ "created_at": "2014-02-06T10:42:46.536Z",
+ "height": 282,
+ "width": 360,
+ "file": "original_images/David_Mitchell_by_Kubik.JPG",
+ "uploaded_by_user": null
+ }
+},
+{
+ "pk": 7,
+ "model": "wagtailimages.image",
+ "fields": {
+ "title": "Wagtail by joe Buckingham",
+ "created_at": "2014-02-06T10:49:29.579Z",
+ "height": 397,
+ "width": 640,
+ "file": "original_images/wagtail_by_joe_buckingham.jpg",
+ "uploaded_by_user": null
+ }
+},
+{
+ "pk": 8,
+ "model": "wagtailimages.image",
+ "fields": {
+ "title": "Wagtail by fs-phil",
+ "created_at": "2014-02-06T10:54:29.963Z",
+ "height": 397,
+ "width": 640,
+ "file": "original_images/wagtail_by_fs-phil.jpg",
+ "uploaded_by_user": null
+ }
+},
+{
+ "pk": 9,
+ "model": "wagtailimages.image",
+ "fields": {
+ "title": "White wagtail by Koshy Koshy",
+ "created_at": "2014-02-06T10:57:05.536Z",
+ "height": 397,
+ "width": 640,
+ "file": "original_images/white_wagtail_by_Koshyk.jpg",
+ "uploaded_by_user": null
+ }
+},
+{
+ "pk": 10,
+ "model": "wagtailimages.image",
+ "fields": {
+ "title": "Pied wagtail by Marie Hale",
+ "created_at": "2014-02-06T11:05:12.370Z",
+ "height": 397,
+ "width": 640,
+ "file": "original_images/pied_wagtail_by_Marie_Hale.jpg",
+ "uploaded_by_user": null
+ }
+},
+{
+ "pk": 11,
+ "model": "wagtailimages.image",
+ "fields": {
+ "title": "Wagtail at Borovoye, Kazakhstan by Ken and Nyetta",
+ "created_at": "2014-02-06T11:08:09.355Z",
+ "height": 397,
+ "width": 640,
+ "file": "original_images/wagtail_at_Borovoye_Kazakhstan_by_Ken_and_Nyetta.jpg",
+ "uploaded_by_user": null
+ }
+},
+{
+ "pk": 12,
+ "model": "wagtailimages.image",
+ "fields": {
+ "title": "Wagtail sproing by Jim Bendon",
+ "created_at": "2014-02-06T11:10:01.185Z",
+ "height": 397,
+ "width": 640,
+ "file": "original_images/wagtail_sproing_by_Jim_Bendon.jpg",
+ "uploaded_by_user": null
+ }
+},
+{
+ "pk": 13,
+ "model": "wagtailimages.image",
+ "fields": {
+ "title": "Hopalong wagtail by Ruth Flickr",
+ "created_at": "2014-02-06T11:15:32.454Z",
+ "height": 397,
+ "width": 640,
+ "file": "original_images/hopalong_wagtail_by_Ruth_Flickr.jpg",
+ "uploaded_by_user": null
+ }
+},
+{
+ "pk": 14,
+ "model": "wagtailimages.image",
+ "fields": {
+ "title": "Wagtail collects insects by Margrit",
+ "created_at": "2014-02-06T11:21:13.596Z",
+ "height": 397,
+ "width": 640,
+ "file": "original_images/wagtail_collects_insects_by_Maggi_94.jpg",
+ "uploaded_by_user": null
+ }
+},
+{
+ "pk": 15,
+ "model": "wagtailimages.image",
+ "fields": {
+ "title": "Grey wagtail by Lip Kee",
+ "created_at": "2014-02-06T11:23:36.409Z",
+ "height": 397,
+ "width": 640,
+ "file": "original_images/grey_wagtail_by_lip_kee.jpg",
+ "uploaded_by_user": null
+ }
+},
+{
+ "pk": 5,
+ "model": "demosite.blogindexpage",
+ "fields": {
+ "intro": "Three species are poly- or paraphyletic in the present taxonomical arrangement and either subspecies need to be reassigned and/or species split up. The Blue-headed Wagtail (AKA Yellow Wagtail and many other names), especially, has always been a taxonomical nightmare with over a dozen currently accepted subspecies and many more invalid ones. The two remaining \"monochrome\" species, Mekong and African Pied Wagtail may be closely related, or a most striking example of convergent evolution.
"
+ }
+},
+{
+ "pk": 1,
+ "model": "demosite.blogindexpagerelatedlink",
+ "fields": {
+ "link_page": 4,
+ "title": "Events index",
+ "link_external": "",
+ "sort_order": 0,
+ "link_document": null,
+ "page": 5
+ }
+},
+{
+ "pk": 16,
+ "model": "demosite.blogentrypage",
+ "fields": {
+ "body": "mtDNA cytochrome b and NADH dehydrogenase subunit 2 sequence data (Voelker, 2002) is of limited use: the suspicion that there is a superspecies of probably 3 white-bellied, black-throated wagtails is confirmed. Also, there is another superspecies in sub-Saharan Africa, three white-throated species with a black breast-band. The remaining five species are highly variable morphologically and their relationships with each other and with the two clades have not yet been satisfactorily explained.
The origin of the genus appears to be in the general area of Eastern Siberia/Mongolia. Wagtails spread rapidly across Eurasia and dispersed to Africa in the Zanclean (Early Pliocene) where the sub-Saharan lineage was later isolated. The African Pied Wagtail (and possibly the Mekong Wagtail) diverged prior to the massive radiation of the white-bellied black-throated and most yellow-bellied forms, all of which took place during the late Piacenzian (early Late Pliocene), c. 3 mya.
mtDNA cytochrome b and NADH dehydrogenase subunit 2 sequence data (Voelker, 2002) is of limited use: the suspicion that there is a superspecies of probably 3 white-bellied, black-throated wagtails is confirmed. Also, there is another superspecies in sub-Saharan Africa, three white-throated species with a black breast-band. The remaining five species are highly variable morphologically and their relationships with each other and with the two clades have not yet been satisfactorily explained.
The origin of the genus appears to be in the general area of Eastern Siberia/Mongolia. Wagtails spread rapidly across Eurasia and dispersed to Africa in the Zanclean (Early Pliocene) where the sub-Saharan lineage was later isolated. The African Pied Wagtail (and possibly the Mekong Wagtail) diverged prior to the massive radiation of the white-bellied black-throated and most yellow-bellied forms, all of which took place during the late Piacenzian (early Late Pliocene), c. 3 mya.
mtDNA cytochrome b and NADH dehydrogenase subunit 2 sequence data (Voelker, 2002) is of limited use: the suspicion that there is a superspecies of probably 3 white-bellied, black-throated wagtails is confirmed. Also, there is another superspecies in sub-Saharan Africa, three white-throated species with a black breast-band. The remaining five species are highly variable morphologically and their relationships with each other and with the two clades have not yet been satisfactorily explained.
The origin of the genus appears to be in the general area of Eastern Siberia/Mongolia. Wagtails spread rapidly across Eurasia and dispersed to Africa in the Zanclean (Early Pliocene) where the sub-Saharan lineage was later isolated. The African Pied Wagtail (and possibly the Mekong Wagtail) diverged prior to the massive radiation of the white-bellied black-throated and most yellow-bellied forms, all of which took place during the late Piacenzian (early Late Pliocene), c. 3 mya.
",
+ "date": "2013-12-02",
+ "feed_image": 7
+ }
+},
+{
+ "pk": 18,
+ "model": "demosite.blogentrypage",
+ "fields": {
+ "body": "Wagtails are slender, often colourful, ground-feeding insectivores of open country in the Old World. They are ground nesters, laying up to six speckled eggs at a time. Among their most conspicuous behaviours is a near constant tail wagging, a trait that has given the birds their common name. In spite of the ubiquity of the behaviour and observations of it, the reasons for it are poorly understood. It has been suggested that it may flush up prey, or that it may signal submissiveness to other wagtails. Recent studies have suggested instead that it is a signal of vigilance that may aid to deter potential predators.
At first glance, the wagtails appear to be divided into a yellow-bellied group and a white-bellied one, or one where the upper head is black and another where it is usually gray, but may be olive, yellow, or other colours. However, these are not evolutionary lineages; change of belly colour and increase of melanin have occurred independently several times in the wagtails, and the colour patterns which actually indicate relationships are more subtle.
mtDNA cytochrome b and NADH dehydrogenase subunit 2 sequence data (Voelker, 2002) is of limited use: the suspicion that there is a superspecies of probably 3 white-bellied, black-throated wagtails is confirmed. Also, there is another superspecies in sub-Saharan Africa, three white-throated species with a black breast-band. The remaining five species are highly variable morphologically and their relationships with each other and with the two clades have not yet been satisfactorily explained.
The origin of the genus appears to be in the general area of Eastern Siberia/Mongolia. Wagtails spread rapidly across Eurasia and dispersed to Africa in the Zanclean (Early Pliocene) where the sub-Saharan lineage was later isolated. The African Pied Wagtail (and possibly the Mekong Wagtail) diverged prior to the massive radiation of the white-bellied black-throated and most yellow-bellied forms, all of which took place during the late Piacenzian (early Late Pliocene), c. 3 mya.
Three species are poly- or paraphyletic in the present taxonomical arrangement and either subspecies need to be reassigned and/or species split up. The Blue-headed Wagtail (AKA Yellow Wagtail and many other names), especially, has always been a taxonomical nightmare with over a dozen currently accepted subspecies and many more invalid ones. The two remaining \"monochrome\" species, Mekong and African Pied Wagtail may be closely related, or a most striking example of convergent evolution.
Prehistoric wagtails known from fossils are Motacilla humata and Motacilla major.
See the species accounts for more on individual species' relationships.
",
+ "date": "2014-01-10",
+ "feed_image": 15
+ }
+},
+{
+ "pk": 19,
+ "model": "demosite.blogentrypage",
+ "fields": {
+ "body": "Wagtails are slender, often colourful, ground-feeding insectivores of open country in the Old World. They are ground nesters, laying up to six speckled eggs at a time. Among their most conspicuous behaviours is a near constant tail wagging, a trait that has given the birds their common name. In spite of the ubiquity of the behaviour and observations of it, the reasons for it are poorly understood. It has been suggested that it may flush up prey, or that it may signal submissiveness to other wagtails. Recent studies have suggested instead that it is a signal of vigilance that may aid to deter potential predators.
At first glance, the wagtails appear to be divided into a yellow-bellied group and a white-bellied one, or one where the upper head is black and another where it is usually gray, but may be olive, yellow, or other colours. However, these are not evolutionary lineages; change of belly colour and increase of melanin have occurred independently several times in the wagtails, and the colour patterns which actually indicate relationships are more subtle.
mtDNA cytochrome b and NADH dehydrogenase subunit 2 sequence data (Voelker, 2002) is of limited use: the suspicion that there is a superspecies of probably 3 white-bellied, black-throated wagtails is confirmed. Also, there is another superspecies in sub-Saharan Africa, three white-throated species with a black breast-band. The remaining five species are highly variable morphologically and their relationships with each other and with the two clades have not yet been satisfactorily explained.
The origin of the genus appears to be in the general area of Eastern Siberia/Mongolia. Wagtails spread rapidly across Eurasia and dispersed to Africa in the Zanclean (Early Pliocene) where the sub-Saharan lineage was later isolated. The African Pied Wagtail (and possibly the Mekong Wagtail) diverged prior to the massive radiation of the white-bellied black-throated and most yellow-bellied forms, all of which took place during the late Piacenzian (early Late Pliocene), c. 3 mya.
Three species are poly- or paraphyletic in the present taxonomical arrangement and either subspecies need to be reassigned and/or species split up. The Blue-headed Wagtail (AKA Yellow Wagtail and many other names), especially, has always been a taxonomical nightmare with over a dozen currently accepted subspecies and many more invalid ones. The two remaining \"monochrome\" species, Mekong and African Pied Wagtail may be closely related, or a most striking example of convergent evolution.
Prehistoric wagtails known from fossils are Motacilla humata and Motacilla major.
See the species accounts for more on individual species' relationships.
",
+ "date": "2014-02-01",
+ "feed_image": 14
+ }
+},
+{
+ "pk": 1,
+ "model": "demosite.blogentrypagecarouselitem",
+ "fields": {
+ "link_page": null,
+ "embed_url": "",
+ "image": 9,
+ "link_external": "http://www.flickr.com/photos/kkoshy/",
+ "caption": "White wagtail by Koshy Koshy",
+ "sort_order": 0,
+ "link_document": null,
+ "page": 16
+ }
+},
+{
+ "pk": 2,
+ "model": "demosite.blogentrypagecarouselitem",
+ "fields": {
+ "link_page": null,
+ "embed_url": "",
+ "image": 7,
+ "link_external": "http://www.flickr.com/photos/jim_bendon_1957/",
+ "caption": "Wagtail by Jim Bendon",
+ "sort_order": 1,
+ "link_document": null,
+ "page": 16
+ }
+},
+{
+ "pk": 4,
+ "model": "demosite.blogentrypagetag",
+ "fields": {
+ "content_object": 19,
+ "tag": 5
+ }
+},
+{
+ "pk": 5,
+ "model": "demosite.blogentrypagetag",
+ "fields": {
+ "content_object": 16,
+ "tag": 4
+ }
+},
+{
+ "pk": 6,
+ "model": "demosite.blogentrypagetag",
+ "fields": {
+ "content_object": 16,
+ "tag": 5
+ }
+},
+{
+ "pk": 7,
+ "model": "demosite.blogentrypagetag",
+ "fields": {
+ "content_object": 18,
+ "tag": 4
+ }
+},
+{
+ "pk": 12,
+ "model": "demosite.contactpage",
+ "fields": {
+ "body": "Wagtails are slender, often colourful, ground-feeding insectivores of open country in the Old World. They are ground nesters, laying up to six speckled eggs at a time. Among their most conspicuous behaviours is a near constant tail wagging, a trait that has given the birds their common name. In spite of the ubiquity of the behaviour and observations of it, the reasons for it are poorly understood. It has been suggested that it may flush up prey, or that it may signal submissiveness to other wagtails. Recent studies have suggested instead that it is a signal of vigilance that may aid to deter potential predators.
",
+ "city": "Birdland",
+ "post_code": "W1A 1AA",
+ "country": "Birdshire",
+ "telephone": "012345 123456",
+ "address_1": "21 Tweety Mansions",
+ "address_2": "3 Bird Lane",
+ "email": "foo@example.com",
+ "feed_image": 7
+ }
+},
+{
+ "pk": 4,
+ "model": "demosite.eventindexpage",
+ "fields": {
+ "intro": "Three species are poly- or paraphyletic in the present taxonomical arrangement and either subspecies need to be reassigned and/or species split up. The Blue-headed Wagtail (AKA Yellow Wagtail and many other names), especially, has always been a taxonomical nightmare with over a dozen currently accepted subspecies and many more invalid ones. The two remaining \"monochrome\" species, Mekong and African Pied Wagtail may be closely related, or a most striking example of convergent evolution.
"
+ }
+},
+{
+ "pk": 8,
+ "model": "demosite.eventpage",
+ "fields": {
+ "body": "Wagtails are slender, often colourful, ground-feeding insectivores of open country in the Old World. They are ground nesters, laying up to six speckled eggs at a time. Among their most conspicuous behaviours is a near constant tail wagging, a trait that has given the birds their common name. In spite of the ubiquity of the behaviour and observations of it, the reasons for it are poorly understood. It has been suggested that it may flush up prey, or that it may signal submissiveness to other wagtails. Recent studies have suggested instead that it is a signal of vigilance that may aid to deter potential predators.
At first glance, the wagtails appear to be divided into a yellow-bellied group and a white-bellied one, or one where the upper head is black and another where it is usually gray, but may be olive, yellow, or other colours. However, these are not evolutionary lineages; change of belly colour and increase of melanin have occurred independently several times in the wagtails, and the colour patterns which actually indicate relationships are more subtle.
",
+ "feed_image": 8,
+ "date_from": "2018-02-28",
+ "time_from": "11:30:00",
+ "audience": "public",
+ "cost": "\u00a330 per person, \u00a310 concessions",
+ "location": "Royal Albert Hall",
+ "date_to": "2018-03-02",
+ "time_to": "19:00:00",
+ "signup_link": "http://www.eventbrite.com/"
+ }
+},
+{
+ "pk": 9,
+ "model": "demosite.eventpage",
+ "fields": {
+ "body": "Three species are poly- or paraphyletic in the present taxonomical arrangement and either subspecies need to be reassigned and/or species split up. The Blue-headed Wagtail (AKA Yellow Wagtail and many other names), especially, has always been a taxonomical nightmare with over a dozen currently accepted subspecies and many more invalid ones. The two remaining \"monochrome\" species, Mekong and African Pied Wagtail may be closely related, or a most striking example of convergent evolution
",
+ "feed_image": 10,
+ "date_from": "2018-04-26",
+ "time_from": null,
+ "audience": "private",
+ "cost": "\u00a350",
+ "location": "O2 Arena",
+ "date_to": null,
+ "time_to": null,
+ "signup_link": ""
+ }
+},
+{
+ "pk": 1,
+ "model": "demosite.eventpagespeaker",
+ "fields": {
+ "last_name": "Joyce",
+ "first_name": "James",
+ "link_page": null,
+ "image": 5,
+ "link_external": "",
+ "sort_order": 0,
+ "link_document": null,
+ "page": 8
+ }
+},
+{
+ "pk": 2,
+ "model": "demosite.eventpagespeaker",
+ "fields": {
+ "last_name": "Mitchell",
+ "first_name": "David",
+ "link_page": null,
+ "image": 6,
+ "link_external": "",
+ "sort_order": 1,
+ "link_document": null,
+ "page": 8
+ }
+},
+{
+ "pk": 2,
+ "model": "demosite.homepage",
+ "fields": {
+ "body": "Wagtails are slender, often colourful, ground-feeding insectivores of open country in the Old World. They are ground nesters, laying up to six speckled eggs at a time. Among their most conspicuous behaviours is a near constant tail wagging, a trait that has given the birds their common name. In spite of the ubiquity of the behaviour and observations of it, the reasons for it are poorly understood. It has been suggested that it may flush up prey, or that it may signal submissiveness to other wagtails. Recent studies have suggested instead that it is a signal of vigilance that may aid to deter potential predators.
"
+ }
+},
+{
+ "pk": 1,
+ "model": "demosite.homepagecarouselitem",
+ "fields": {
+ "link_page": null,
+ "embed_url": "",
+ "image": 15,
+ "link_external": "http://www.flickr.com/photos/lipkee/",
+ "caption": "Grey wagtail by Lip Kee",
+ "sort_order": 0,
+ "link_document": null,
+ "page": 2
+ }
+},
+{
+ "pk": 2,
+ "model": "demosite.homepagecarouselitem",
+ "fields": {
+ "link_page": null,
+ "embed_url": "",
+ "image": 12,
+ "link_external": "http://www.flickr.com/photos/jim_bendon_1957/",
+ "caption": "Wagtail sproing by Jim Bendon",
+ "sort_order": 1,
+ "link_document": null,
+ "page": 2
+ }
+},
+{
+ "pk": 3,
+ "model": "demosite.homepagecarouselitem",
+ "fields": {
+ "link_page": null,
+ "embed_url": "",
+ "image": 11,
+ "link_external": "http://www.flickr.com/photos/kjfnjy/",
+ "caption": "Wagtail at Borovoye, Kazakhstan by Ken and Nyetta",
+ "sort_order": 2,
+ "link_document": null,
+ "page": 2
+ }
+},
+{
+ "pk": 13,
+ "model": "demosite.personpage",
+ "fields": {
+ "feed_image": 5,
+ "city": "Birdland",
+ "first_name": "James",
+ "post_code": "W1A 1AA",
+ "country": "Birdshire",
+ "image": 5,
+ "telephone": "012345 123456",
+ "last_name": "Joyce",
+ "address_1": "21 Tweety Mansions",
+ "address_2": "3 Bird Lane",
+ "intro": "The origin of the genus appears to be in the general area of Eastern Siberia/Mongolia. Wagtails spread rapidly across Eurasia and dispersed to Africa in the Zanclean
",
+ "email": "foo@example.com",
+ "biography": "Wagtails are slender, often colourful, ground-feeding insectivores of open country in the Old World. They are ground nesters, laying up to six speckled eggs at a time. Among their most conspicuous behaviours is a near constant tail wagging, a trait that has given the birds their common name. In spite of the ubiquity of the behaviour and observations of it, the reasons for it are poorly understood. It has been suggested that it may flush up prey, or that it may signal submissiveness to other wagtails. Recent studies have suggested instead that it is a signal of vigilance that may aid to deter potential predators.
At first glance, the wagtails appear to be divided into a yellow-bellied group and a white-bellied one, or one where the upper head is black and another where it is usually gray, but may be olive, yellow, or other colours. However, these are not evolutionary lineages; change of belly colour and increase of melanin have occurred independently several times in the wagtails, and the colour patterns which actually indicate relationships are more subtle.
"
+ }
+},
+{
+ "pk": 14,
+ "model": "demosite.personpage",
+ "fields": {
+ "feed_image": 6,
+ "city": "",
+ "first_name": "David",
+ "post_code": "W1A 1AA",
+ "country": "",
+ "image": 6,
+ "telephone": "",
+ "last_name": "Mitchell",
+ "address_1": "",
+ "address_2": "",
+ "intro": "Wagtails are slender, often colourful, ground-feeding insectivores of open country in the Old World.
",
+ "email": "foo@example.com",
+ "biography": "Wagtails are slender, often colourful, ground-feeding insectivores of open country in the Old World. They are ground nesters, laying up to six speckled eggs at a time. Among their most conspicuous behaviours is a near constant tail wagging, a trait that has given the birds their common name. In spite of the ubiquity of the behaviour and observations of it, the reasons for it are poorly understood. It has been suggested that it may flush up prey, or that it may signal submissiveness to other wagtails. Recent studies have suggested instead that it is a signal of vigilance that may aid to deter potential predators.
"
+ }
+},
+{
+ "pk": 6,
+ "model": "demosite.standardindexpage",
+ "fields": {
+ "feed_image": null,
+ "intro": "Three species are poly- or paraphyletic in the present taxonomical arrangement and either subspecies need to be reassigned and/or species split up. The Blue-headed Wagtail (AKA Yellow Wagtail and many other names), especially, has always been a taxonomical nightmare with over a dozen currently accepted subspecies and many more invalid ones. The two remaining \"monochrome\" species, Mekong and African Pied Wagtail may be closely related, or a most striking example of convergent evolution.
"
+ }
+},
+{
+ "pk": 20,
+ "model": "demosite.standardindexpage",
+ "fields": {
+ "feed_image": null,
+ "intro": ""
+ }
+},
+{
+ "pk": 21,
+ "model": "demosite.standardindexpage",
+ "fields": {
+ "feed_image": null,
+ "intro": "A listing of pages at the next level down
"
+ }
+},
+{
+ "pk": 10,
+ "model": "demosite.standardpage",
+ "fields": {
+ "body": "Wagtails are slender, often colourful, ground-feeding insectivores of open country in the Old World. They are ground nesters, laying up to six speckled eggs at a time. Among their most conspicuous behaviours is a near constant tail wagging, a trait that has given the birds their common name. In spite of the ubiquity of the behaviour and observations of it, the reasons for it are poorly understood. It has been suggested that it may flush up prey, or that it may signal submissiveness to other wagtails. Recent studies have suggested instead that it is a signal of vigilance that may aid to deter potential predators.
At first glance, the wagtails appear to be divided into a yellow-bellied group and a white-bellied one, or one where the upper head is black and another where it is usually gray, but may be olive, yellow, or other colours. However, these are not evolutionary lineages; change of belly colour and increase of melanin have occurred independently several times in the wagtails, and the colour patterns which actually indicate relationships are more subtle.
mtDNA cytochrome b and NADH dehydrogenase subunit 2 sequence data (Voelker, 2002) is of limited use: the suspicion that there is a superspecies of probably 3 white-bellied, black-throated wagtails is confirmed. Also, there is another superspecies in sub-Saharan Africa, three white-throated species with a black breast-band. The remaining five species are highly variable morphologically and their relationships with each other and with the two clades have not yet been satisfactorily explained.
The origin of the genus appears to be in the general area of Eastern Siberia/Mongolia. Wagtails spread rapidly across Eurasia and dispersed to Africa in the Zanclean (Early Pliocene) where the sub-Saharan lineage was later isolated. The African Pied Wagtail (and possibly the Mekong Wagtail) diverged prior to the massive radiation of the white-bellied black-throated and most yellow-bellied forms, all of which took place during the late Piacenzian (early Late Pliocene), c. 3 mya.
",
+ "feed_image": 12,
+ "intro": "At first glance, the wagtails appear to be divided into a yellow-bellied group and a white-bellied one, or one where the upper head is black and another where it is usually gray, but may be olive, yellow, or other colours. However, these are not evolutionary lineages; change of belly colour and increase of melanin have occurred independently several times in the wagtails, and the colour patterns which actually indicate relationships are more subtle.
"
+ }
+},
+{
+ "pk": 15,
+ "model": "demosite.standardpage",
+ "fields": {
+ "body": "Wagtails are great
At first glance, the wagtails appear to be divided into a yellow-bellied group and a white-bellied one, or one where the upper head is black and another where it is usually gray, but may be olive, yellow, or other colours. However, these are not evolutionary lineages; change of belly colour and increase of melanin have occurred independently several times in the wagtails, and the colour patterns which actually indicate relationships are more subtle.
Wagtails are pretty
mtDNA cytochrome b and NADH dehydrogenase subunit 2 sequence data (Voelker, 2002) is of limited use: the suspicion that there is a superspecies of probably 3 white-bellied, black-throated wagtails is confirmed. Also, there is another superspecies in sub-Saharan Africa, three white-throated species with a black breast-band. The remaining five species are highly variable morphologically and their relationships with each other and with the two clades have not yet been satisfactorily explained.
The origin of the genus appears to be in the general area of Eastern Siberia/Mongolia. Wagtails spread rapidly across Eurasia and dispersed to Africa in the Zanclean (Early Pliocene) where the sub-Saharan lineage was later isolated. The African Pied Wagtail (and possibly the Mekong Wagtail) diverged prior to the massive radiation of the white-bellied black-throated and most yellow-bellied forms, all of which took place during the late Piacenzian (early Late Pliocene), c. 3 mya.
Three species are poly- or paraphyletic in the present taxonomical arrangement and either subspecies need to be reassigned and/or species split up. The Blue-headed Wagtail (AKA Yellow Wagtail and many other names), especially, has always been a taxonomical nightmare with over a dozen currently accepted subspecies and many more invalid ones. The two remaining \"monochrome\" species, Mekong and African Pied Wagtail may be closely related, or a most striking example of convergent evolution.
",
+ "feed_image": 10,
+ "intro": "The remaining five species are highly variable morphologically and their relationships with each other and with the two clades have not yet been satisfactorily explained.
"
+ }
+},
+{
+ "pk": 17,
+ "model": "demosite.standardpage",
+ "fields": {
+ "body": "
James Joyce,\u00a01915,\u00a0Cornell Joyce Collection\u00a0by C. Ruf - public domain in the United States
\nDavid Mitchell (b. 1969), British writer,\u00a0Warsaw (Poland), April 7, 2006, \u00a0Mariusz Kubik, GDFL licence
Wagtail,\u00a0October 14, 2012\u00a0by Mark Harkin, \u00a0\u00a0Creative Commons
Wagtail, February 18th 2008, by Joe Buckingham, Creative Commons
Wagtail, August 4th 2009, by fs-phil, Creative Commons
White wagtail, February 5th 2012, by Koshy Koshy, Creative Commons
Pied wagtail, January 20th 2013, by Marie Hale, Creative Commons
Wagtail at Borovoye, Kazakhstan, June 16th 2012, by Ken and Nyetta,\u00a0Creative Commons
Wagtail sproing, April 29 2012, by Jim Bendon, Creative Commons
Hopalong wagtail, June 17th 2008, by Ruth Flickr, Creative Commons
Wagtail collects insects, June 10th 2010, by Margrit, Creative Commons
Grey wagtail, March 13th 2009, by Lip Kee, Creative Commons
",
+ "feed_image": 15,
+ "intro": "The following photos have been used in the sample wagtailapi tests database
"
+ }
+},
+{
+ "pk": 22,
+ "model": "demosite.standardpage",
+ "fields": {
+ "body": "The origin of the genus appears to be in the general area of Eastern Siberia/Mongolia. Wagtails spread rapidly across Eurasia and dispersed to Africa in the Zanclean (Early Pliocene) where the sub-Saharan lineage was later isolated. The African Pied Wagtail (and possibly the Mekong Wagtail) diverged prior to the massive radiation of the white-bellied black-throated and most yellow-bellied forms, all of which took place during the late Piacenzian (early Late Pliocene), c. 3 mya.
Three species are poly- or paraphyletic in the present taxonomical arrangement and either subspecies need to be reassigned and/or species split up. The Blue-headed Wagtail (AKA Yellow Wagtail and many other names), especially, has always been a taxonomical nightmare with over a dozen currently accepted subspecies and many more invalid ones. The two remaining \"monochrome\" species, Mekong and African Pied Wagtail may be closely related, or a most striking example of convergent evolution.
",
+ "feed_image": null,
+ "intro": "At first glance, the wagtails appear to be divided into a yellow-bellied group and a white-bellied one, or one where the upper head is black and another where it is usually gray, but may be olive, yellow, or other colours.
"
+ }
+},
+{
+ "pk": 23,
+ "model": "demosite.standardpage",
+ "fields": {
+ "body": "The origin of the genus appears to be in the general area of Eastern Siberia/Mongolia. Wagtails spread rapidly across Eurasia and dispersed to Africa in the Zanclean (Early Pliocene) where the sub-Saharan lineage was later isolated. The African Pied Wagtail (and possibly the Mekong Wagtail) diverged prior to the massive radiation of the white-bellied black-throated and most yellow-bellied forms, all of which took place during the late Piacenzian (early Late Pliocene), c. 3 mya.
Three species are poly- or paraphyletic in the present taxonomical arrangement and either subspecies need to be reassigned and/or species split up. The Blue-headed Wagtail (AKA Yellow Wagtail and many other names), especially, has always been a taxonomical nightmare with over a dozen currently accepted subspecies and many more invalid ones. The two remaining \"monochrome\" species, Mekong and African Pied Wagtail may be closely related, or a most striking example of convergent evolution.
",
+ "feed_image": null,
+ "intro": "The origin of the genus appears to be in the general area of Eastern Siberia/Mongolia. Wagtails spread rapidly across Eurasia and dispersed to Africa in the Zanclean (Early Pliocene) where the sub-Saharan lineage was later isolated. The African Pied Wagtail (and possibly the Mekong Wagtail) diverged prior to the massive radiation of the white-bellied black-throated and most yellow-bellied forms, all of which took place during the late Piacenzian (early Late Pliocene), c. 3 mya.
"
+ }
+},
+{
+ "pk": 1,
+ "model": "demosite.standardpagecarouselitem",
+ "fields": {
+ "link_page": null,
+ "embed_url": "",
+ "image": 13,
+ "link_external": "http://www.flickr.com/photos/ruthhb/",
+ "caption": "Hopalong wagtail by Ruth Flickr",
+ "sort_order": 0,
+ "link_document": null,
+ "page": 10
+ }
+},
+{
+ "pk": 2,
+ "model": "demosite.standardpagecarouselitem",
+ "fields": {
+ "link_page": null,
+ "embed_url": "",
+ "image": 15,
+ "link_external": "http://www.flickr.com/photos/lipkee/",
+ "caption": "Grey wagtail by Lip Kee",
+ "sort_order": 1,
+ "link_document": null,
+ "page": 10
+ }
+},
+{
+ "pk": 1,
+ "model": "demosite.standardpagerelatedlink",
+ "fields": {
+ "link_page": 4,
+ "title": "Internal link to events",
+ "link_external": "",
+ "sort_order": 0,
+ "link_document": null,
+ "page": 10
+ }
+},
+{
+ "pk": 2,
+ "model": "demosite.standardpagerelatedlink",
+ "fields": {
+ "link_page": null,
+ "title": "External link to google",
+ "link_external": "http://www.google.com/",
+ "sort_order": 1,
+ "link_document": null,
+ "page": 10
+ }
+},
+{
+ "pk": 1,
+ "model": "taggit.tag",
+ "fields": {
+ "name": "writers",
+ "slug": "writers"
+ }
+},
+{
+ "pk": 2,
+ "model": "taggit.tag",
+ "fields": {
+ "name": "people",
+ "slug": "people"
+ }
+},
+{
+ "pk": 3,
+ "model": "taggit.tag",
+ "fields": {
+ "name": "person",
+ "slug": "person"
+ }
+},
+{
+ "pk": 4,
+ "model": "taggit.tag",
+ "fields": {
+ "name": "wagtail",
+ "slug": "wagtail"
+ }
+},
+{
+ "pk": 5,
+ "model": "taggit.tag",
+ "fields": {
+ "name": "bird",
+ "slug": "bird"
+ }
+},
+{
+ "pk": 6,
+ "model": "taggit.tag",
+ "fields": {
+ "name": "writer",
+ "slug": "writer"
+ }
+},
+{
+ "pk": 1,
+ "model": "wagtaildocs.document",
+ "fields": {
+ "title": "Wagtail by mark Harkin",
+ "created_at": "2014-02-06T10:14:47.173Z",
+ "file": "original_images/wagtail_by_markyharky.jpg",
+ "uploaded_by_user": null
+ }
+},
+{
+ "pk": 2,
+ "model": "wagtaildocs.document",
+ "fields": {
+ "title": "James Joyce",
+ "created_at": "2014-02-06T10:37:10.518Z",
+ "file": "original_images/James_Joyce_in_1915.jpg",
+ "uploaded_by_user": null
+ }
+},
+{
+ "pk": 3,
+ "model": "wagtaildocs.document",
+ "fields": {
+ "title": "David Mitchell",
+ "created_at": "2014-02-06T10:42:46.536Z",
+ "file": "original_images/David_Mitchell_by_Kubik.JPG",
+ "uploaded_by_user": null
+ }
+},
+{
+ "pk": 4,
+ "model": "wagtaildocs.document",
+ "fields": {
+ "title": "Wagtail by joe Buckingham",
+ "created_at": "2014-02-06T10:49:29.579Z",
+ "file": "original_images/wagtail_by_joe_buckingham.jpg",
+ "uploaded_by_user": null
+ }
+},
+{
+ "pk": 5,
+ "model": "wagtaildocs.document",
+ "fields": {
+ "title": "Wagtail by fs-phil",
+ "created_at": "2014-02-06T10:54:29.963Z",
+ "file": "original_images/wagtail_by_fs-phil.jpg",
+ "uploaded_by_user": null
+ }
+},
+{
+ "pk": 6,
+ "model": "wagtaildocs.document",
+ "fields": {
+ "title": "White wagtail by Koshy Koshy",
+ "created_at": "2014-02-06T10:57:05.536Z",
+ "file": "original_images/white_wagtail_by_Koshyk.jpg",
+ "uploaded_by_user": null
+ }
+},
+{
+ "pk": 7,
+ "model": "wagtaildocs.document",
+ "fields": {
+ "title": "Pied wagtail by Marie Hale",
+ "created_at": "2014-02-06T11:05:12.370Z",
+ "file": "original_images/pied_wagtail_by_Marie_Hale.jpg",
+ "uploaded_by_user": null
+ }
+},
+{
+ "pk": 8,
+ "model": "wagtaildocs.document",
+ "fields": {
+ "title": "Wagtail at Borovoye, Kazakhstan by Ken and Nyetta",
+ "created_at": "2014-02-06T11:08:09.355Z",
+ "file": "original_images/wagtail_at_Borovoye_Kazakhstan_by_Ken_and_Nyetta.jpg",
+ "uploaded_by_user": null
+ }
+},
+{
+ "pk": 9,
+ "model": "wagtaildocs.document",
+ "fields": {
+ "title": "Wagtail sproing by Jim Bendon",
+ "created_at": "2014-02-06T11:10:01.185Z",
+ "file": "original_images/wagtail_sproing_by_Jim_Bendon.jpg",
+ "uploaded_by_user": null
+ }
+},
+{
+ "pk": 10,
+ "model": "wagtaildocs.document",
+ "fields": {
+ "title": "Hopalong wagtail by Ruth Flickr",
+ "created_at": "2014-02-06T11:15:32.454Z",
+ "file": "original_images/hopalong_wagtail_by_Ruth_Flickr.jpg",
+ "uploaded_by_user": null
+ }
+},
+{
+ "pk": 11,
+ "model": "wagtaildocs.document",
+ "fields": {
+ "title": "Wagtail collects insects by Margrit",
+ "created_at": "2014-02-06T11:21:13.596Z",
+ "file": "original_images/wagtail_collects_insects_by_Maggi_94.jpg",
+ "uploaded_by_user": null
+ }
+},
+{
+ "pk": 12,
+ "model": "wagtaildocs.document",
+ "fields": {
+ "title": "Grey wagtail by Lip Kee",
+ "created_at": "2014-02-06T11:23:36.409Z",
+ "file": "original_images/grey_wagtail_by_lip_kee.jpg",
+ "uploaded_by_user": null
+ }
+}
+]
diff --git a/wagtail/tests/demosite/migrations/0001_initial.py b/wagtail/tests/demosite/migrations/0001_initial.py
new file mode 100644
index 000000000..a7eb7c757
--- /dev/null
+++ b/wagtail/tests/demosite/migrations/0001_initial.py
@@ -0,0 +1,513 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+import django.db.models.deletion
+import modelcluster.tags
+import wagtail.wagtailcore.fields
+import modelcluster.fields
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('wagtailimages', '0005_make_filter_spec_unique'),
+ ('taggit', '0001_initial'),
+ ('wagtaildocs', '0002_initial_data'),
+ ('wagtailcore', '0013_update_golive_expire_help_text'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='BlogEntryPage',
+ fields=[
+ ('page_ptr', models.OneToOneField(to='wagtailcore.Page', serialize=False, parent_link=True, related_name='+', primary_key=True)),
+ ('body', wagtail.wagtailcore.fields.RichTextField()),
+ ('date', models.DateField(verbose_name='Post date')),
+ ('feed_image', models.ForeignKey(to='wagtailimages.Image', blank=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', null=True)),
+ ],
+ options={
+ 'abstract': False,
+ },
+ bases=('wagtailcore.page',),
+ ),
+ migrations.CreateModel(
+ name='BlogEntryPageCarouselItem',
+ fields=[
+ ('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)),
+ ('sort_order', models.IntegerField(null=True, editable=False, blank=True)),
+ ('link_external', models.URLField(blank=True, verbose_name='External link')),
+ ('embed_url', models.URLField(blank=True, verbose_name='Embed URL')),
+ ('caption', models.CharField(blank=True, max_length=255)),
+ ('image', models.ForeignKey(to='wagtailimages.Image', blank=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', null=True)),
+ ('link_document', models.ForeignKey(to='wagtaildocs.Document', blank=True, related_name='+', null=True)),
+ ],
+ options={
+ 'ordering': ['sort_order'],
+ 'abstract': False,
+ },
+ bases=(models.Model,),
+ ),
+ migrations.CreateModel(
+ name='BlogEntryPageRelatedLink',
+ fields=[
+ ('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)),
+ ('sort_order', models.IntegerField(null=True, editable=False, blank=True)),
+ ('link_external', models.URLField(blank=True, verbose_name='External link')),
+ ('title', models.CharField(help_text='Link title', max_length=255)),
+ ('link_document', models.ForeignKey(to='wagtaildocs.Document', blank=True, related_name='+', null=True)),
+ ],
+ options={
+ 'ordering': ['sort_order'],
+ 'abstract': False,
+ },
+ bases=(models.Model,),
+ ),
+ migrations.CreateModel(
+ name='BlogEntryPageTag',
+ fields=[
+ ('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)),
+ ('content_object', modelcluster.fields.ParentalKey(to='demosite.BlogEntryPage', related_name='tagged_items')),
+ ('tag', models.ForeignKey(to='taggit.Tag', related_name='demosite_blogentrypagetag_items')),
+ ],
+ options={
+ 'abstract': False,
+ },
+ bases=(models.Model,),
+ ),
+ migrations.CreateModel(
+ name='BlogIndexPage',
+ fields=[
+ ('page_ptr', models.OneToOneField(to='wagtailcore.Page', serialize=False, parent_link=True, related_name='+', primary_key=True)),
+ ('intro', wagtail.wagtailcore.fields.RichTextField(blank=True)),
+ ],
+ options={
+ 'abstract': False,
+ },
+ bases=('wagtailcore.page',),
+ ),
+ migrations.CreateModel(
+ name='BlogIndexPageRelatedLink',
+ fields=[
+ ('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)),
+ ('sort_order', models.IntegerField(null=True, editable=False, blank=True)),
+ ('link_external', models.URLField(blank=True, verbose_name='External link')),
+ ('title', models.CharField(help_text='Link title', max_length=255)),
+ ('link_document', models.ForeignKey(to='wagtaildocs.Document', blank=True, related_name='+', null=True)),
+ ],
+ options={
+ 'ordering': ['sort_order'],
+ 'abstract': False,
+ },
+ bases=(models.Model,),
+ ),
+ migrations.CreateModel(
+ name='ContactPage',
+ fields=[
+ ('telephone', models.CharField(blank=True, max_length=20)),
+ ('email', models.EmailField(blank=True, max_length=75)),
+ ('address_1', models.CharField(blank=True, max_length=255)),
+ ('address_2', models.CharField(blank=True, max_length=255)),
+ ('city', models.CharField(blank=True, max_length=255)),
+ ('country', models.CharField(blank=True, max_length=255)),
+ ('post_code', models.CharField(blank=True, max_length=10)),
+ ('page_ptr', models.OneToOneField(to='wagtailcore.Page', serialize=False, parent_link=True, related_name='+', primary_key=True)),
+ ('body', wagtail.wagtailcore.fields.RichTextField(blank=True)),
+ ('feed_image', models.ForeignKey(to='wagtailimages.Image', blank=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', null=True)),
+ ],
+ options={
+ 'abstract': False,
+ },
+ bases=('wagtailcore.page', models.Model),
+ ),
+ migrations.CreateModel(
+ name='EventIndexPage',
+ fields=[
+ ('page_ptr', models.OneToOneField(to='wagtailcore.Page', serialize=False, parent_link=True, related_name='+', primary_key=True)),
+ ('intro', wagtail.wagtailcore.fields.RichTextField(blank=True)),
+ ],
+ options={
+ 'abstract': False,
+ },
+ bases=('wagtailcore.page',),
+ ),
+ migrations.CreateModel(
+ name='EventIndexPageRelatedLink',
+ fields=[
+ ('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)),
+ ('sort_order', models.IntegerField(null=True, editable=False, blank=True)),
+ ('link_external', models.URLField(blank=True, verbose_name='External link')),
+ ('title', models.CharField(help_text='Link title', max_length=255)),
+ ('link_document', models.ForeignKey(to='wagtaildocs.Document', blank=True, related_name='+', null=True)),
+ ],
+ options={
+ 'ordering': ['sort_order'],
+ 'abstract': False,
+ },
+ bases=(models.Model,),
+ ),
+ migrations.CreateModel(
+ name='EventPage',
+ fields=[
+ ('page_ptr', models.OneToOneField(to='wagtailcore.Page', serialize=False, parent_link=True, related_name='+', primary_key=True)),
+ ('date_from', models.DateField(verbose_name='Start date')),
+ ('date_to', models.DateField(help_text='Not required if event is on a single day', null=True, verbose_name='End date', blank=True)),
+ ('time_from', models.TimeField(null=True, verbose_name='Start time', blank=True)),
+ ('time_to', models.TimeField(null=True, verbose_name='End time', blank=True)),
+ ('audience', models.CharField(choices=[('public', 'Public'), ('private', 'Private')], max_length=255)),
+ ('location', models.CharField(max_length=255)),
+ ('body', wagtail.wagtailcore.fields.RichTextField(blank=True)),
+ ('cost', models.CharField(max_length=255)),
+ ('signup_link', models.URLField(blank=True)),
+ ('feed_image', models.ForeignKey(to='wagtailimages.Image', blank=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', null=True)),
+ ],
+ options={
+ 'abstract': False,
+ },
+ bases=('wagtailcore.page',),
+ ),
+ migrations.CreateModel(
+ name='EventPageCarouselItem',
+ fields=[
+ ('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)),
+ ('sort_order', models.IntegerField(null=True, editable=False, blank=True)),
+ ('link_external', models.URLField(blank=True, verbose_name='External link')),
+ ('embed_url', models.URLField(blank=True, verbose_name='Embed URL')),
+ ('caption', models.CharField(blank=True, max_length=255)),
+ ('image', models.ForeignKey(to='wagtailimages.Image', blank=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', null=True)),
+ ('link_document', models.ForeignKey(to='wagtaildocs.Document', blank=True, related_name='+', null=True)),
+ ],
+ options={
+ 'ordering': ['sort_order'],
+ 'abstract': False,
+ },
+ bases=(models.Model,),
+ ),
+ migrations.CreateModel(
+ name='EventPageRelatedLink',
+ fields=[
+ ('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)),
+ ('sort_order', models.IntegerField(null=True, editable=False, blank=True)),
+ ('link_external', models.URLField(blank=True, verbose_name='External link')),
+ ('title', models.CharField(help_text='Link title', max_length=255)),
+ ('link_document', models.ForeignKey(to='wagtaildocs.Document', blank=True, related_name='+', null=True)),
+ ],
+ options={
+ 'ordering': ['sort_order'],
+ 'abstract': False,
+ },
+ bases=(models.Model,),
+ ),
+ migrations.CreateModel(
+ name='EventPageSpeaker',
+ fields=[
+ ('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)),
+ ('sort_order', models.IntegerField(null=True, editable=False, blank=True)),
+ ('link_external', models.URLField(blank=True, verbose_name='External link')),
+ ('first_name', models.CharField(blank=True, verbose_name='Name', max_length=255)),
+ ('last_name', models.CharField(blank=True, verbose_name='Surname', max_length=255)),
+ ('image', models.ForeignKey(to='wagtailimages.Image', blank=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', null=True)),
+ ('link_document', models.ForeignKey(to='wagtaildocs.Document', blank=True, related_name='+', null=True)),
+ ],
+ options={
+ 'ordering': ['sort_order'],
+ 'abstract': False,
+ },
+ bases=(models.Model,),
+ ),
+ migrations.CreateModel(
+ name='HomePage',
+ fields=[
+ ('page_ptr', models.OneToOneField(to='wagtailcore.Page', serialize=False, parent_link=True, related_name='+', primary_key=True)),
+ ('body', wagtail.wagtailcore.fields.RichTextField(blank=True)),
+ ],
+ options={
+ 'verbose_name': 'Homepage',
+ },
+ bases=('wagtailcore.page',),
+ ),
+ migrations.CreateModel(
+ name='HomePageCarouselItem',
+ fields=[
+ ('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)),
+ ('sort_order', models.IntegerField(null=True, editable=False, blank=True)),
+ ('link_external', models.URLField(blank=True, verbose_name='External link')),
+ ('embed_url', models.URLField(blank=True, verbose_name='Embed URL')),
+ ('caption', models.CharField(blank=True, max_length=255)),
+ ('image', models.ForeignKey(to='wagtailimages.Image', blank=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', null=True)),
+ ('link_document', models.ForeignKey(to='wagtaildocs.Document', blank=True, related_name='+', null=True)),
+ ],
+ options={
+ 'ordering': ['sort_order'],
+ 'abstract': False,
+ },
+ bases=(models.Model,),
+ ),
+ migrations.CreateModel(
+ name='HomePageRelatedLink',
+ fields=[
+ ('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)),
+ ('sort_order', models.IntegerField(null=True, editable=False, blank=True)),
+ ('link_external', models.URLField(blank=True, verbose_name='External link')),
+ ('title', models.CharField(help_text='Link title', max_length=255)),
+ ('link_document', models.ForeignKey(to='wagtaildocs.Document', blank=True, related_name='+', null=True)),
+ ],
+ options={
+ 'ordering': ['sort_order'],
+ 'abstract': False,
+ },
+ bases=(models.Model,),
+ ),
+ migrations.CreateModel(
+ name='PersonPage',
+ fields=[
+ ('telephone', models.CharField(blank=True, max_length=20)),
+ ('email', models.EmailField(blank=True, max_length=75)),
+ ('address_1', models.CharField(blank=True, max_length=255)),
+ ('address_2', models.CharField(blank=True, max_length=255)),
+ ('city', models.CharField(blank=True, max_length=255)),
+ ('country', models.CharField(blank=True, max_length=255)),
+ ('post_code', models.CharField(blank=True, max_length=10)),
+ ('page_ptr', models.OneToOneField(to='wagtailcore.Page', serialize=False, parent_link=True, related_name='+', primary_key=True)),
+ ('first_name', models.CharField(max_length=255)),
+ ('last_name', models.CharField(max_length=255)),
+ ('intro', wagtail.wagtailcore.fields.RichTextField(blank=True)),
+ ('biography', wagtail.wagtailcore.fields.RichTextField(blank=True)),
+ ('feed_image', models.ForeignKey(to='wagtailimages.Image', blank=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', null=True)),
+ ('image', models.ForeignKey(to='wagtailimages.Image', blank=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', null=True)),
+ ],
+ options={
+ 'abstract': False,
+ },
+ bases=('wagtailcore.page', models.Model),
+ ),
+ migrations.CreateModel(
+ name='PersonPageRelatedLink',
+ fields=[
+ ('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)),
+ ('sort_order', models.IntegerField(null=True, editable=False, blank=True)),
+ ('link_external', models.URLField(blank=True, verbose_name='External link')),
+ ('title', models.CharField(help_text='Link title', max_length=255)),
+ ('link_document', models.ForeignKey(to='wagtaildocs.Document', blank=True, related_name='+', null=True)),
+ ],
+ options={
+ 'ordering': ['sort_order'],
+ 'abstract': False,
+ },
+ bases=(models.Model,),
+ ),
+ migrations.CreateModel(
+ name='StandardIndexPage',
+ fields=[
+ ('page_ptr', models.OneToOneField(to='wagtailcore.Page', serialize=False, parent_link=True, related_name='+', primary_key=True)),
+ ('intro', wagtail.wagtailcore.fields.RichTextField(blank=True)),
+ ('feed_image', models.ForeignKey(to='wagtailimages.Image', blank=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', null=True)),
+ ],
+ options={
+ 'abstract': False,
+ },
+ bases=('wagtailcore.page',),
+ ),
+ migrations.CreateModel(
+ name='StandardIndexPageRelatedLink',
+ fields=[
+ ('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)),
+ ('sort_order', models.IntegerField(null=True, editable=False, blank=True)),
+ ('link_external', models.URLField(blank=True, verbose_name='External link')),
+ ('title', models.CharField(help_text='Link title', max_length=255)),
+ ('link_document', models.ForeignKey(to='wagtaildocs.Document', blank=True, related_name='+', null=True)),
+ ],
+ options={
+ 'ordering': ['sort_order'],
+ 'abstract': False,
+ },
+ bases=(models.Model,),
+ ),
+ migrations.CreateModel(
+ name='StandardPage',
+ fields=[
+ ('page_ptr', models.OneToOneField(to='wagtailcore.Page', serialize=False, parent_link=True, related_name='+', primary_key=True)),
+ ('intro', wagtail.wagtailcore.fields.RichTextField(blank=True)),
+ ('body', wagtail.wagtailcore.fields.RichTextField(blank=True)),
+ ('feed_image', models.ForeignKey(to='wagtailimages.Image', blank=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', null=True)),
+ ],
+ options={
+ 'abstract': False,
+ },
+ bases=('wagtailcore.page',),
+ ),
+ migrations.CreateModel(
+ name='StandardPageCarouselItem',
+ fields=[
+ ('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)),
+ ('sort_order', models.IntegerField(null=True, editable=False, blank=True)),
+ ('link_external', models.URLField(blank=True, verbose_name='External link')),
+ ('embed_url', models.URLField(blank=True, verbose_name='Embed URL')),
+ ('caption', models.CharField(blank=True, max_length=255)),
+ ('image', models.ForeignKey(to='wagtailimages.Image', blank=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', null=True)),
+ ('link_document', models.ForeignKey(to='wagtaildocs.Document', blank=True, related_name='+', null=True)),
+ ('link_page', models.ForeignKey(to='wagtailcore.Page', blank=True, related_name='+', null=True)),
+ ('page', modelcluster.fields.ParentalKey(to='demosite.StandardPage', related_name='carousel_items')),
+ ],
+ options={
+ 'ordering': ['sort_order'],
+ 'abstract': False,
+ },
+ bases=(models.Model,),
+ ),
+ migrations.CreateModel(
+ name='StandardPageRelatedLink',
+ fields=[
+ ('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)),
+ ('sort_order', models.IntegerField(null=True, editable=False, blank=True)),
+ ('link_external', models.URLField(blank=True, verbose_name='External link')),
+ ('title', models.CharField(help_text='Link title', max_length=255)),
+ ('link_document', models.ForeignKey(to='wagtaildocs.Document', blank=True, related_name='+', null=True)),
+ ('link_page', models.ForeignKey(to='wagtailcore.Page', blank=True, related_name='+', null=True)),
+ ('page', modelcluster.fields.ParentalKey(to='demosite.StandardPage', related_name='related_links')),
+ ],
+ options={
+ 'ordering': ['sort_order'],
+ 'abstract': False,
+ },
+ bases=(models.Model,),
+ ),
+ migrations.AddField(
+ model_name='standardindexpagerelatedlink',
+ name='link_page',
+ field=models.ForeignKey(to='wagtailcore.Page', blank=True, related_name='+', null=True),
+ preserve_default=True,
+ ),
+ migrations.AddField(
+ model_name='standardindexpagerelatedlink',
+ name='page',
+ field=modelcluster.fields.ParentalKey(to='demosite.StandardIndexPage', related_name='related_links'),
+ preserve_default=True,
+ ),
+ migrations.AddField(
+ model_name='personpagerelatedlink',
+ name='link_page',
+ field=models.ForeignKey(to='wagtailcore.Page', blank=True, related_name='+', null=True),
+ preserve_default=True,
+ ),
+ migrations.AddField(
+ model_name='personpagerelatedlink',
+ name='page',
+ field=modelcluster.fields.ParentalKey(to='demosite.PersonPage', related_name='related_links'),
+ preserve_default=True,
+ ),
+ migrations.AddField(
+ model_name='homepagerelatedlink',
+ name='link_page',
+ field=models.ForeignKey(to='wagtailcore.Page', blank=True, related_name='+', null=True),
+ preserve_default=True,
+ ),
+ migrations.AddField(
+ model_name='homepagerelatedlink',
+ name='page',
+ field=modelcluster.fields.ParentalKey(to='demosite.HomePage', related_name='related_links'),
+ preserve_default=True,
+ ),
+ migrations.AddField(
+ model_name='homepagecarouselitem',
+ name='link_page',
+ field=models.ForeignKey(to='wagtailcore.Page', blank=True, related_name='+', null=True),
+ preserve_default=True,
+ ),
+ migrations.AddField(
+ model_name='homepagecarouselitem',
+ name='page',
+ field=modelcluster.fields.ParentalKey(to='demosite.HomePage', related_name='carousel_items'),
+ preserve_default=True,
+ ),
+ migrations.AddField(
+ model_name='eventpagespeaker',
+ name='link_page',
+ field=models.ForeignKey(to='wagtailcore.Page', blank=True, related_name='+', null=True),
+ preserve_default=True,
+ ),
+ migrations.AddField(
+ model_name='eventpagespeaker',
+ name='page',
+ field=modelcluster.fields.ParentalKey(to='demosite.EventPage', related_name='speakers'),
+ preserve_default=True,
+ ),
+ migrations.AddField(
+ model_name='eventpagerelatedlink',
+ name='link_page',
+ field=models.ForeignKey(to='wagtailcore.Page', blank=True, related_name='+', null=True),
+ preserve_default=True,
+ ),
+ migrations.AddField(
+ model_name='eventpagerelatedlink',
+ name='page',
+ field=modelcluster.fields.ParentalKey(to='demosite.EventPage', related_name='related_links'),
+ preserve_default=True,
+ ),
+ migrations.AddField(
+ model_name='eventpagecarouselitem',
+ name='link_page',
+ field=models.ForeignKey(to='wagtailcore.Page', blank=True, related_name='+', null=True),
+ preserve_default=True,
+ ),
+ migrations.AddField(
+ model_name='eventpagecarouselitem',
+ name='page',
+ field=modelcluster.fields.ParentalKey(to='demosite.EventPage', related_name='carousel_items'),
+ preserve_default=True,
+ ),
+ migrations.AddField(
+ model_name='eventindexpagerelatedlink',
+ name='link_page',
+ field=models.ForeignKey(to='wagtailcore.Page', blank=True, related_name='+', null=True),
+ preserve_default=True,
+ ),
+ migrations.AddField(
+ model_name='eventindexpagerelatedlink',
+ name='page',
+ field=modelcluster.fields.ParentalKey(to='demosite.EventIndexPage', related_name='related_links'),
+ preserve_default=True,
+ ),
+ migrations.AddField(
+ model_name='blogindexpagerelatedlink',
+ name='link_page',
+ field=models.ForeignKey(to='wagtailcore.Page', blank=True, related_name='+', null=True),
+ preserve_default=True,
+ ),
+ migrations.AddField(
+ model_name='blogindexpagerelatedlink',
+ name='page',
+ field=modelcluster.fields.ParentalKey(to='demosite.BlogIndexPage', related_name='related_links'),
+ preserve_default=True,
+ ),
+ migrations.AddField(
+ model_name='blogentrypagerelatedlink',
+ name='link_page',
+ field=models.ForeignKey(to='wagtailcore.Page', blank=True, related_name='+', null=True),
+ preserve_default=True,
+ ),
+ migrations.AddField(
+ model_name='blogentrypagerelatedlink',
+ name='page',
+ field=modelcluster.fields.ParentalKey(to='demosite.BlogEntryPage', related_name='related_links'),
+ preserve_default=True,
+ ),
+ migrations.AddField(
+ model_name='blogentrypagecarouselitem',
+ name='link_page',
+ field=models.ForeignKey(to='wagtailcore.Page', blank=True, related_name='+', null=True),
+ preserve_default=True,
+ ),
+ migrations.AddField(
+ model_name='blogentrypagecarouselitem',
+ name='page',
+ field=modelcluster.fields.ParentalKey(to='demosite.BlogEntryPage', related_name='carousel_items'),
+ preserve_default=True,
+ ),
+ migrations.AddField(
+ model_name='blogentrypage',
+ name='tags',
+ field=modelcluster.tags.ClusterTaggableManager(help_text='A comma-separated list of tags.', through='demosite.BlogEntryPageTag', blank=True, verbose_name='Tags', to='taggit.Tag'),
+ preserve_default=True,
+ ),
+ ]
diff --git a/wagtail/tests/demosite/migrations/__init__.py b/wagtail/tests/demosite/migrations/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/wagtail/tests/demosite/models.py b/wagtail/tests/demosite/models.py
new file mode 100644
index 000000000..724e61600
--- /dev/null
+++ b/wagtail/tests/demosite/models.py
@@ -0,0 +1,594 @@
+from django.db import models
+from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
+
+from modelcluster.fields import ParentalKey
+from modelcluster.tags import ClusterTaggableManager
+from taggit.models import Tag, TaggedItemBase
+
+from wagtail.wagtailcore.models import Page, Orderable
+from wagtail.wagtailcore.fields import RichTextField
+from wagtail.wagtailadmin.edit_handlers import FieldPanel, MultiFieldPanel, \
+ InlinePanel, PageChooserPanel
+from wagtail.wagtailimages.edit_handlers import ImageChooserPanel
+from wagtail.wagtaildocs.edit_handlers import DocumentChooserPanel
+from wagtail.wagtailsnippets.models import register_snippet
+from wagtail.wagtailforms.models import AbstractEmailForm, AbstractFormField
+from wagtail.wagtailsearch import index
+
+
+# ABSTRACT MODELS
+# =============================
+
+class AbstractLinkFields(models.Model):
+ link_external = models.URLField("External link", blank=True)
+ link_page = models.ForeignKey(
+ 'wagtailcore.Page',
+ null=True,
+ blank=True,
+ related_name='+'
+ )
+ link_document = models.ForeignKey(
+ 'wagtaildocs.Document',
+ null=True,
+ blank=True,
+ related_name='+'
+ )
+
+ @property
+ def link(self):
+ if self.link_page:
+ return self.link_page.url
+ elif self.link_document:
+ return self.link_document.url
+ else:
+ return self.link_external
+
+ api_fields = ('link', )
+
+ panels = [
+ FieldPanel('link_external'),
+ PageChooserPanel('link_page'),
+ DocumentChooserPanel('link_document'),
+ ]
+
+ class Meta:
+ abstract = True
+
+
+class AbstractRelatedLink(AbstractLinkFields):
+ title = models.CharField(max_length=255, help_text="Link title")
+
+ api_fields = ('title', ) + AbstractLinkFields.api_fields
+
+ panels = [
+ FieldPanel('title'),
+ MultiFieldPanel(AbstractLinkFields.panels, "Link"),
+ ]
+
+ class Meta:
+ abstract = True
+
+
+class AbstractCarouselItem(AbstractLinkFields):
+ image = models.ForeignKey(
+ 'wagtailimages.Image',
+ null=True,
+ blank=True,
+ on_delete=models.SET_NULL,
+ related_name='+'
+ )
+ embed_url = models.URLField("Embed URL", blank=True)
+ caption = models.CharField(max_length=255, blank=True)
+
+ api_fields = (
+ 'image',
+ 'embed_url',
+ 'caption',
+ ) + AbstractLinkFields.api_fields
+
+ panels = [
+ ImageChooserPanel('image'),
+ FieldPanel('embed_url'),
+ FieldPanel('caption'),
+ MultiFieldPanel(AbstractLinkFields.panels, "Link"),
+ ]
+
+ class Meta:
+ abstract = True
+
+
+class ContactFieldsMixin(models.Model):
+ telephone = models.CharField(max_length=20, blank=True)
+ email = models.EmailField(blank=True)
+ address_1 = models.CharField(max_length=255, blank=True)
+ address_2 = models.CharField(max_length=255, blank=True)
+ city = models.CharField(max_length=255, blank=True)
+ country = models.CharField(max_length=255, blank=True)
+ post_code = models.CharField(max_length=10, blank=True)
+
+ api_fields = (
+ 'telephone',
+ 'email',
+ 'address_1',
+ 'address_2',
+ 'city',
+ 'country',
+ 'post_code',
+ )
+
+ panels = [
+ FieldPanel('telephone'),
+ FieldPanel('email'),
+ FieldPanel('address_1'),
+ FieldPanel('address_2'),
+ FieldPanel('city'),
+ FieldPanel('country'),
+ FieldPanel('post_code'),
+ ]
+
+ class Meta:
+ abstract = True
+
+
+# PAGE MODELS
+# =============================
+
+# Home page
+
+class HomePage(Page):
+ page_ptr = models.OneToOneField(Page, parent_link=True, related_name='+')
+ body = RichTextField(blank=True)
+
+ api_fields = (
+ 'body',
+ 'carousel_items',
+ 'related_links',
+ )
+
+ search_fields = Page.search_fields + (
+ index.SearchField('body'),
+ )
+
+ class Meta:
+ verbose_name = "Homepage"
+
+
+class HomePageCarouselItem(Orderable, AbstractCarouselItem):
+ page = ParentalKey('HomePage', related_name='carousel_items')
+
+class HomePageRelatedLink(Orderable, AbstractRelatedLink):
+ page = ParentalKey('HomePage', related_name='related_links')
+
+HomePage.content_panels = Page.content_panels + [
+ FieldPanel('body', classname="full"),
+
+ InlinePanel(HomePage, 'carousel_items', label="Carousel items"),
+ InlinePanel(HomePage, 'related_links', label="Related links"),
+]
+
+
+# Standard pages
+
+class StandardPage(Page):
+ page_ptr = models.OneToOneField(Page, parent_link=True, related_name='+')
+ intro = RichTextField(blank=True)
+ body = RichTextField(blank=True)
+ feed_image = models.ForeignKey(
+ 'wagtailimages.Image',
+ null=True,
+ blank=True,
+ on_delete=models.SET_NULL,
+ related_name='+'
+ )
+
+ api_fields = (
+ 'intro',
+ 'body',
+ 'feed_image',
+ 'carousel_items',
+ 'related_links',
+ )
+
+ search_fields = Page.search_fields + (
+ index.SearchField('intro'),
+ index.SearchField('body'),
+ )
+
+class StandardPageCarouselItem(Orderable, AbstractCarouselItem):
+ page = ParentalKey('StandardPage', related_name='carousel_items')
+
+class StandardPageRelatedLink(Orderable, AbstractRelatedLink):
+ page = ParentalKey('StandardPage', related_name='related_links')
+
+StandardPage.content_panels = Page.content_panels + [
+ FieldPanel('intro', classname="full"),
+ InlinePanel(StandardPage, 'carousel_items', label="Carousel items"),
+ FieldPanel('body', classname="full"),
+ InlinePanel(StandardPage, 'related_links', label="Related links"),
+]
+
+StandardPage.promote_panels = [
+ MultiFieldPanel(Page.promote_panels, "Common page configuration"),
+ ImageChooserPanel('feed_image'),
+]
+
+
+class StandardIndexPage(Page):
+ page_ptr = models.OneToOneField(Page, parent_link=True, related_name='+')
+ intro = RichTextField(blank=True)
+ feed_image = models.ForeignKey(
+ 'wagtailimages.Image',
+ null=True,
+ blank=True,
+ on_delete=models.SET_NULL,
+ related_name='+'
+ )
+
+ api_fields = (
+ 'intro',
+ 'feed_image',
+ 'related_links',
+ )
+
+ search_fields = Page.search_fields + (
+ index.SearchField('intro'),
+ )
+
+class StandardIndexPageRelatedLink(Orderable, AbstractRelatedLink):
+ page = ParentalKey('StandardIndexPage', related_name='related_links')
+
+StandardIndexPage.content_panels = Page.content_panels + [
+ FieldPanel('intro', classname="full"),
+ InlinePanel(StandardIndexPage, 'related_links', label="Related links"),
+]
+
+StandardIndexPage.promote_panels = [
+ MultiFieldPanel(Page.promote_panels, "Common page configuration"),
+ ImageChooserPanel('feed_image'),
+]
+
+
+# Blog pages
+
+class BlogEntryPage(Page):
+ page_ptr = models.OneToOneField(Page, parent_link=True, related_name='+')
+ body = RichTextField()
+ tags = ClusterTaggableManager(through='BlogEntryPageTag', blank=True)
+ date = models.DateField("Post date")
+ feed_image = models.ForeignKey(
+ 'wagtailimages.Image',
+ null=True,
+ blank=True,
+ on_delete=models.SET_NULL,
+ related_name='+'
+ )
+
+ api_fields = (
+ 'body',
+ 'tags',
+ 'date',
+ 'feed_image',
+ 'carousel_items',
+ 'related_links',
+ )
+
+ search_fields = Page.search_fields + (
+ index.SearchField('body'),
+ )
+
+ def get_blog_index(self):
+ # Find closest ancestor which is a blog index
+ return BlogIndexPage.ancestor_of(self).last()
+
+class BlogEntryPageCarouselItem(Orderable, AbstractCarouselItem):
+ page = ParentalKey('BlogEntryPage', related_name='carousel_items')
+
+class BlogEntryPageRelatedLink(Orderable, AbstractRelatedLink):
+ page = ParentalKey('BlogEntryPage', related_name='related_links')
+
+class BlogEntryPageTag(TaggedItemBase):
+ content_object = ParentalKey('BlogEntryPage', related_name='tagged_items')
+
+BlogEntryPage.content_panels = Page.content_panels + [
+ FieldPanel('date'),
+ FieldPanel('body', classname="full"),
+ InlinePanel(BlogEntryPage, 'carousel_items', label="Carousel items"),
+ InlinePanel(BlogEntryPage, 'related_links', label="Related links"),
+]
+
+BlogEntryPage.promote_panels = [
+ MultiFieldPanel(Page.promote_panels, "Common page configuration"),
+ ImageChooserPanel('feed_image'),
+ FieldPanel('tags'),
+]
+
+
+class BlogIndexPage(Page):
+ page_ptr = models.OneToOneField(Page, parent_link=True, related_name='+')
+ intro = RichTextField(blank=True)
+
+ api_fields = (
+ 'intro',
+ 'related_links',
+ )
+
+ search_fields = Page.search_fields + (
+ index.SearchField('intro'),
+ )
+
+ def get_blog_entries(self):
+ # Get list of live blog pages that are descendants of this page
+ entries = BlogEntryPage.objects.descendant_of(self).live()
+
+ # Order by most recent date first
+ entries = entries.order_by('-date')
+
+ return entries
+
+ def get_context(self, request):
+ # Get blog entries
+ entries = self.get_blog_entries()
+
+ # Filter by tag
+ tag = request.GET.get('tag')
+ if tag:
+ entries = entries.filter(tags__name=tag)
+
+ # Pagination
+ page = request.GET.get('page')
+ paginator = Paginator(entries, 10) # Show 10 entries per page
+ try:
+ entries = paginator.page(page)
+ except PageNotAnInteger:
+ entries = paginator.page(1)
+ except EmptyPage:
+ entries = paginator.page(paginator.num_pages)
+
+ # Update template context
+ context = super(BlogIndexPage, self).get_context(request)
+ context['entries'] = entries
+ return context
+
+class BlogIndexPageRelatedLink(Orderable, AbstractRelatedLink):
+ page = ParentalKey('BlogIndexPage', related_name='related_links')
+
+BlogIndexPage.content_panels = Page.content_panels + [
+ FieldPanel('intro', classname="full"),
+ InlinePanel(BlogIndexPage, 'related_links', label="Related links"),
+]
+
+
+# Events pages
+
+class EventPage(Page):
+ page_ptr = models.OneToOneField(Page, parent_link=True, related_name='+')
+ AUDIENCE_CHOICES = (
+ ('public', "Public"),
+ ('private', "Private"),
+ )
+
+ date_from = models.DateField("Start date")
+ date_to = models.DateField(
+ "End date",
+ null=True,
+ blank=True,
+ help_text="Not required if event is on a single day"
+ )
+ time_from = models.TimeField("Start time", null=True, blank=True)
+ time_to = models.TimeField("End time", null=True, blank=True)
+ audience = models.CharField(max_length=255, choices=AUDIENCE_CHOICES)
+ location = models.CharField(max_length=255)
+ body = RichTextField(blank=True)
+ cost = models.CharField(max_length=255)
+ signup_link = models.URLField(blank=True)
+ feed_image = models.ForeignKey(
+ 'wagtailimages.Image',
+ null=True,
+ blank=True,
+ on_delete=models.SET_NULL,
+ related_name='+'
+ )
+
+ api_fields = (
+ 'date_from',
+ 'date_to',
+ 'time_from',
+ 'time_to',
+ 'audience',
+ 'location',
+ 'body',
+ 'cost',
+ 'signup_link',
+ 'feed_image',
+ 'carousel_items',
+ 'related_links',
+ 'speakers',
+ )
+
+ search_fields = Page.search_fields + (
+ index.SearchField('get_audience_display'),
+ index.SearchField('location'),
+ index.SearchField('body'),
+ )
+
+ def get_event_index(self):
+ # Find closest ancestor which is an event index
+ return EventIndexPage.objects.ancester_of(self).last()
+
+class EventPageCarouselItem(Orderable, AbstractCarouselItem):
+ page = ParentalKey('EventPage', related_name='carousel_items')
+
+class EventPageRelatedLink(Orderable, AbstractRelatedLink):
+ page = ParentalKey('EventPage', related_name='related_links')
+
+class EventPageSpeaker(Orderable, AbstractLinkFields):
+ page = ParentalKey('EventPage', related_name='speakers')
+ first_name = models.CharField("Name", max_length=255, blank=True)
+ last_name = models.CharField("Surname", max_length=255, blank=True)
+ image = models.ForeignKey(
+ 'wagtailimages.Image',
+ null=True,
+ blank=True,
+ on_delete=models.SET_NULL,
+ related_name='+'
+ )
+
+ api_fields = (
+ 'first_name',
+ 'last_name',
+ 'image',
+ )
+
+ panels = [
+ FieldPanel('first_name'),
+ FieldPanel('last_name'),
+ ImageChooserPanel('image'),
+ MultiFieldPanel(AbstractLinkFields.panels, "Link"),
+ ]
+
+EventPage.content_panels = Page.content_panels + [
+ FieldPanel('date_from'),
+ FieldPanel('date_to'),
+ FieldPanel('time_from'),
+ FieldPanel('time_to'),
+ FieldPanel('location'),
+ FieldPanel('audience'),
+ FieldPanel('cost'),
+ FieldPanel('signup_link'),
+ InlinePanel(EventPage, 'carousel_items', label="Carousel items"),
+ FieldPanel('body', classname="full"),
+ InlinePanel(EventPage, 'speakers', label="Speakers"),
+ InlinePanel(EventPage, 'related_links', label="Related links"),
+]
+
+EventPage.promote_panels = [
+ MultiFieldPanel(Page.promote_panels, "Common page configuration"),
+ ImageChooserPanel('feed_image'),
+]
+
+
+class EventIndexPage(Page):
+ page_ptr = models.OneToOneField(Page, parent_link=True, related_name='+')
+ intro = RichTextField(blank=True)
+
+ api_fields = (
+ 'intro',
+ 'related_links',
+ )
+
+ search_fields = Page.search_fields + (
+ index.SearchField('intro'),
+ )
+
+ def get_events(self):
+ # Get list of live event pages that are descendants of this page
+ events = EventPage.objects.descendant_of(self).live()
+
+ # Filter events list to get ones that are either
+ # running now or start in the future
+ events = events.filter(date_from__gte=date.today())
+
+ # Order by date
+ events = events.order_by('date_from')
+
+ return events
+
+class EventIndexPageRelatedLink(Orderable, AbstractRelatedLink):
+ page = ParentalKey('EventIndexPage', related_name='related_links')
+
+EventIndexPage.content_panels = Page.content_panels + [
+ FieldPanel('intro', classname="full"),
+ InlinePanel(EventIndexPage, 'related_links', label="Related links"),
+]
+
+
+# Person page
+
+class PersonPage(Page, ContactFieldsMixin):
+ page_ptr = models.OneToOneField(Page, parent_link=True, related_name='+')
+ first_name = models.CharField(max_length=255)
+ last_name = models.CharField(max_length=255)
+ intro = RichTextField(blank=True)
+ biography = RichTextField(blank=True)
+ image = models.ForeignKey(
+ 'wagtailimages.Image',
+ null=True,
+ blank=True,
+ on_delete=models.SET_NULL,
+ related_name='+'
+ )
+ feed_image = models.ForeignKey(
+ 'wagtailimages.Image',
+ null=True,
+ blank=True,
+ on_delete=models.SET_NULL,
+ related_name='+'
+ )
+
+ api_fields = (
+ 'first_name',
+ 'last_name',
+ 'intro',
+ 'biography',
+ 'image',
+ 'feed_image',
+ 'related_links',
+ ) + ContactFieldsMixin.api_fields
+
+ search_fields = Page.search_fields + (
+ index.SearchField('first_name'),
+ index.SearchField('last_name'),
+ index.SearchField('intro'),
+ index.SearchField('biography'),
+ )
+
+class PersonPageRelatedLink(Orderable, AbstractRelatedLink):
+ page = ParentalKey('PersonPage', related_name='related_links')
+
+PersonPage.content_panels = Page.content_panels + [
+ FieldPanel('first_name'),
+ FieldPanel('last_name'),
+ FieldPanel('intro', classname="full"),
+ FieldPanel('biography', classname="full"),
+ ImageChooserPanel('image'),
+ MultiFieldPanel(ContactFieldsMixin.panels, "Contact"),
+ InlinePanel(PersonPage, 'related_links', label="Related links"),
+]
+
+PersonPage.promote_panels = [
+ MultiFieldPanel(Page.promote_panels, "Common page configuration"),
+ ImageChooserPanel('feed_image'),
+]
+
+
+# Contact page
+
+class ContactPage(Page, ContactFieldsMixin):
+ page_ptr = models.OneToOneField(Page, parent_link=True, related_name='+')
+ body = RichTextField(blank=True)
+ feed_image = models.ForeignKey(
+ 'wagtailimages.Image',
+ null=True,
+ blank=True,
+ on_delete=models.SET_NULL,
+ related_name='+'
+ )
+
+ api_fields = (
+ 'body',
+ 'feed_image',
+ ) + ContactFieldsMixin.api_fields
+
+ search_fields = Page.search_fields + (
+ index.SearchField('body'),
+ )
+
+ContactPage.content_panels = Page.content_panels + [
+ FieldPanel('body', classname="full"),
+ MultiFieldPanel(ContactFieldsMixin.panels, "Contact"),
+]
+
+ContactPage.promote_panels = [
+ MultiFieldPanel(Page.promote_panels, "Common page configuration"),
+ ImageChooserPanel('feed_image'),
+]
diff --git a/wagtail/tests/migrations/0003_auto_20140905_0634.py b/wagtail/tests/migrations/0003_auto_20140905_0634.py
deleted file mode 100644
index c1f69f529..000000000
--- a/wagtail/tests/migrations/0003_auto_20140905_0634.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# -*- coding: utf-8 -*-
-from __future__ import unicode_literals
-
-from django.db import models, migrations
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('tests', '0002_auto_20140827_0908'),
- ]
-
- operations = [
- migrations.AddField(
- model_name='advertplacement',
- name='colour',
- field=models.CharField(default='blue', max_length=255),
- preserve_default=False,
- ),
- ]
diff --git a/wagtail/tests/migrations/0004_auto_20141008_0420.py b/wagtail/tests/migrations/0004_auto_20141008_0420.py
deleted file mode 100644
index d5002a776..000000000
--- a/wagtail/tests/migrations/0004_auto_20141008_0420.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# -*- coding: utf-8 -*-
-from __future__ import unicode_literals
-
-from django.db import models, migrations
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('tests', '0003_auto_20140905_0634'),
- ]
-
- operations = [
- migrations.DeleteModel(
- name='SearchTestOldConfig',
- ),
- migrations.DeleteModel(
- name='SearchTestOldConfigList',
- ),
- ]
diff --git a/wagtail/tests/migrations/0005_auto_20141008_0122.py b/wagtail/tests/migrations/0005_auto_20141008_0122.py
deleted file mode 100644
index 801e1f5df..000000000
--- a/wagtail/tests/migrations/0005_auto_20141008_0122.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# -*- coding: utf-8 -*-
-from __future__ import unicode_literals
-
-from django.db import models, migrations
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('wagtailcore', '0002_initial_data'),
- ('tests', '0004_auto_20141008_0420'),
- ]
-
- operations = [
- migrations.CreateModel(
- name='PageChooserModel',
- fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('page', models.ForeignKey(help_text=b'help text', to='wagtailcore.Page')),
- ],
- options={
- },
- bases=(models.Model,),
- ),
- migrations.CreateModel(
- name='SnippetChooserModel',
- fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('advert', models.ForeignKey(help_text=b'help text', to='tests.Advert')),
- ],
- options={
- },
- bases=(models.Model,),
- ),
- ]
diff --git a/wagtail/tests/migrations/0005_auto_20141113_0642.py b/wagtail/tests/migrations/0005_auto_20141113_0642.py
deleted file mode 100644
index 37f5744c8..000000000
--- a/wagtail/tests/migrations/0005_auto_20141113_0642.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# -*- coding: utf-8 -*-
-from __future__ import unicode_literals
-
-from django.db import models, migrations
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('wagtailcore', '0002_initial_data'),
- ('tests', '0004_auto_20141008_0420'),
- ]
-
- operations = [
- migrations.AlterField(
- model_name='formfield',
- name='choices',
- field=models.CharField(help_text='Comma separated list of choices. Only applicable in checkboxes, radio and dropdown.', max_length=512, blank=True),
- preserve_default=True,
- ),
- migrations.AlterField(
- model_name='formfield',
- name='default_value',
- field=models.CharField(help_text='Default value. Comma separated values supported for checkboxes.', max_length=255, blank=True),
- preserve_default=True,
- ),
- ]
diff --git a/wagtail/tests/migrations/0006_merge.py b/wagtail/tests/migrations/0006_merge.py
deleted file mode 100644
index 7489198a7..000000000
--- a/wagtail/tests/migrations/0006_merge.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# -*- coding: utf-8 -*-
-from __future__ import unicode_literals
-
-from django.db import models, migrations
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('tests', '0005_auto_20141113_0642'),
- ('tests', '0005_auto_20141008_0122'),
- ]
-
- operations = [
- ]
diff --git a/wagtail/tests/migrations/0007_auto_20141118_0925.py b/wagtail/tests/migrations/0007_auto_20141118_0925.py
deleted file mode 100644
index be6775130..000000000
--- a/wagtail/tests/migrations/0007_auto_20141118_0925.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# -*- coding: utf-8 -*-
-from __future__ import unicode_literals
-
-from django.db import models, migrations
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('tests', '0006_merge'),
- ]
-
- operations = [
- migrations.AlterField(
- model_name='pagechoosermodel',
- name='page',
- field=models.ForeignKey(to='wagtailcore.Page', help_text='help text'),
- preserve_default=True,
- ),
- migrations.AlterField(
- model_name='snippetchoosermodel',
- name='advert',
- field=models.ForeignKey(to='tests.Advert', help_text='help text'),
- preserve_default=True,
- ),
- ]
diff --git a/wagtail/tests/migrations/0008_registerdecorator.py b/wagtail/tests/migrations/0008_registerdecorator.py
deleted file mode 100644
index c82debdf8..000000000
--- a/wagtail/tests/migrations/0008_registerdecorator.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# -*- coding: utf-8 -*-
-from __future__ import unicode_literals
-
-from django.db import models, migrations
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('tests', '0007_auto_20141118_0925'),
- ]
-
- operations = [
- migrations.CreateModel(
- name='RegisterDecorator',
- fields=[
- ('id', models.AutoField(serialize=False, auto_created=True, verbose_name='ID', primary_key=True)),
- ],
- options={
- },
- bases=(models.Model,),
- ),
- migrations.CreateModel(
- name='RegisterFunction',
- fields=[
- ('id', models.AutoField(serialize=False, auto_created=True, verbose_name='ID', primary_key=True)),
- ],
- options={
- },
- bases=(models.Model,),
- ),
- ]
diff --git a/wagtail/tests/migrations/0009_eventpagechoosermodel.py b/wagtail/tests/migrations/0009_eventpagechoosermodel.py
deleted file mode 100644
index 6b6e505d7..000000000
--- a/wagtail/tests/migrations/0009_eventpagechoosermodel.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# -*- coding: utf-8 -*-
-from __future__ import unicode_literals
-
-from django.db import models, migrations
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('tests', '0008_registerdecorator'),
- ]
-
- operations = [
- migrations.CreateModel(
- name='EventPageChooserModel',
- fields=[
- ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
- ('page', models.ForeignKey(help_text='more help text', to='tests.EventPage')),
- ],
- options={
- },
- bases=(models.Model,),
- ),
- ]
diff --git a/wagtail/tests/migrations/0010_customimagewithadminformfields_customimagewithoutadminformfields.py b/wagtail/tests/migrations/0010_customimagewithadminformfields_customimagewithoutadminformfields.py
deleted file mode 100644
index 1b7f7c9b9..000000000
--- a/wagtail/tests/migrations/0010_customimagewithadminformfields_customimagewithoutadminformfields.py
+++ /dev/null
@@ -1,65 +0,0 @@
-# -*- coding: utf-8 -*-
-from __future__ import unicode_literals
-
-from django.db import models, migrations
-import wagtail.wagtailadmin.taggable
-from django.conf import settings
-import taggit.managers
-import wagtail.wagtailimages.models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('taggit', '0001_initial'),
- ('tests', '0009_eventpagechoosermodel'),
- ]
-
- operations = [
- migrations.CreateModel(
- name='CustomImageWithAdminFormFields',
- fields=[
- ('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)),
- ('title', models.CharField(verbose_name='Title', max_length=255)),
- ('file', models.ImageField(verbose_name='File', height_field='height', upload_to=wagtail.wagtailimages.models.get_upload_to, width_field='width')),
- ('width', models.IntegerField(editable=False)),
- ('height', models.IntegerField(editable=False)),
- ('created_at', models.DateTimeField(auto_now_add=True)),
- ('focal_point_x', models.PositiveIntegerField(blank=True, null=True)),
- ('focal_point_y', models.PositiveIntegerField(blank=True, null=True)),
- ('focal_point_width', models.PositiveIntegerField(blank=True, null=True)),
- ('focal_point_height', models.PositiveIntegerField(blank=True, null=True)),
- ('caption', models.CharField(max_length=255)),
- ('not_editable_field', models.CharField(max_length=255)),
- ('tags', taggit.managers.TaggableManager(verbose_name='Tags', help_text=None, through='taggit.TaggedItem', blank=True, to='taggit.Tag')),
- ('uploaded_by_user', models.ForeignKey(to=settings.AUTH_USER_MODEL, null=True, blank=True, editable=False)),
- ],
- options={
- 'abstract': False,
- },
- bases=(models.Model, wagtail.wagtailadmin.taggable.TagSearchable),
- ),
- migrations.CreateModel(
- name='CustomImageWithoutAdminFormFields',
- fields=[
- ('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)),
- ('title', models.CharField(verbose_name='Title', max_length=255)),
- ('file', models.ImageField(verbose_name='File', height_field='height', upload_to=wagtail.wagtailimages.models.get_upload_to, width_field='width')),
- ('width', models.IntegerField(editable=False)),
- ('height', models.IntegerField(editable=False)),
- ('created_at', models.DateTimeField(auto_now_add=True)),
- ('focal_point_x', models.PositiveIntegerField(blank=True, null=True)),
- ('focal_point_y', models.PositiveIntegerField(blank=True, null=True)),
- ('focal_point_width', models.PositiveIntegerField(blank=True, null=True)),
- ('focal_point_height', models.PositiveIntegerField(blank=True, null=True)),
- ('caption', models.CharField(max_length=255)),
- ('not_editable_field', models.CharField(max_length=255)),
- ('tags', taggit.managers.TaggableManager(verbose_name='Tags', help_text=None, through='taggit.TaggedItem', blank=True, to='taggit.Tag')),
- ('uploaded_by_user', models.ForeignKey(to=settings.AUTH_USER_MODEL, null=True, blank=True, editable=False)),
- ],
- options={
- 'abstract': False,
- },
- bases=(models.Model, wagtail.wagtailadmin.taggable.TagSearchable),
- ),
- ]
diff --git a/wagtail/tests/routablepage/__init__.py b/wagtail/tests/routablepage/__init__.py
new file mode 100644
index 000000000..87fe2ba4a
--- /dev/null
+++ b/wagtail/tests/routablepage/__init__.py
@@ -0,0 +1 @@
+default_app_config = 'wagtail.tests.routablepage.apps.WagtailRoutablePageTestsAppConfig'
diff --git a/wagtail/tests/routablepage/apps.py b/wagtail/tests/routablepage/apps.py
new file mode 100644
index 000000000..8a9f69be8
--- /dev/null
+++ b/wagtail/tests/routablepage/apps.py
@@ -0,0 +1,7 @@
+from django.apps import AppConfig
+
+
+class WagtailRoutablePageTestsAppConfig(AppConfig):
+ name = 'wagtail.tests.routablepage'
+ label = 'routablepagetests'
+ verbose_name = "Wagtail routable page tests"
diff --git a/wagtail/tests/routablepage/migrations/0001_initial.py b/wagtail/tests/routablepage/migrations/0001_initial.py
new file mode 100644
index 000000000..6d5bdfa87
--- /dev/null
+++ b/wagtail/tests/routablepage/migrations/0001_initial.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+import wagtail.contrib.wagtailroutablepage.models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('wagtailcore', '0013_update_golive_expire_help_text'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='RoutablePageTest',
+ fields=[
+ ('page_ptr', models.OneToOneField(to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True, parent_link=True)),
+ ],
+ options={
+ 'abstract': False,
+ },
+ bases=(wagtail.contrib.wagtailroutablepage.models.RoutablePageMixin, 'wagtailcore.page'),
+ ),
+ ]
diff --git a/wagtail/tests/routablepage/migrations/__init__.py b/wagtail/tests/routablepage/migrations/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/wagtail/tests/routablepage/models.py b/wagtail/tests/routablepage/models.py
new file mode 100644
index 000000000..0a3c3692c
--- /dev/null
+++ b/wagtail/tests/routablepage/models.py
@@ -0,0 +1,28 @@
+from django.db import models
+from django.http import HttpResponse
+from django.conf.urls import url
+
+from wagtail.contrib.wagtailroutablepage.models import RoutablePage
+
+
+def routable_page_external_view(request, arg):
+ return HttpResponse("EXTERNAL VIEW: " + arg)
+
+class RoutablePageTest(RoutablePage):
+ @property
+ def subpage_urls(self):
+ return (
+ url(r'^$', self.main, name='main'),
+ url(r'^archive/year/(\d+)/$', self.archive_by_year, name='archive_by_year'),
+ url(r'^archive/author/(?P.+)/$', self.archive_by_author, name='archive_by_author'),
+ url(r'^external/(.+)/$', routable_page_external_view, name='external_view')
+ )
+
+ def archive_by_year(self, request, year):
+ return HttpResponse("ARCHIVE BY YEAR: " + str(year))
+
+ def archive_by_author(self, request, author_slug):
+ return HttpResponse("ARCHIVE BY AUTHOR: " + author_slug)
+
+ def main(self, request):
+ return HttpResponse("MAIN VIEW")
diff --git a/wagtail/tests/search/__init__.py b/wagtail/tests/search/__init__.py
new file mode 100644
index 000000000..f28f75cff
--- /dev/null
+++ b/wagtail/tests/search/__init__.py
@@ -0,0 +1 @@
+default_app_config = 'wagtail.tests.search.apps.WagtailSearchTestsAppConfig'
diff --git a/wagtail/tests/search/apps.py b/wagtail/tests/search/apps.py
new file mode 100644
index 000000000..a8e8c5ee3
--- /dev/null
+++ b/wagtail/tests/search/apps.py
@@ -0,0 +1,7 @@
+from django.apps import AppConfig
+
+
+class WagtailSearchTestsAppConfig(AppConfig):
+ name = 'wagtail.tests.search'
+ label = 'searchtests'
+ verbose_name = "Wagtail search tests"
diff --git a/wagtail/tests/search/migrations/0001_initial.py b/wagtail/tests/search/migrations/0001_initial.py
new file mode 100644
index 000000000..6359e5355
--- /dev/null
+++ b/wagtail/tests/search/migrations/0001_initial.py
@@ -0,0 +1,38 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+import wagtail.wagtailsearch.index
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='SearchTest',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, verbose_name='ID', serialize=False)),
+ ('title', models.CharField(max_length=255)),
+ ('content', models.TextField()),
+ ('live', models.BooleanField(default=False)),
+ ('published_date', models.DateField(null=True)),
+ ],
+ options={
+ },
+ bases=(models.Model, wagtail.wagtailsearch.index.Indexed),
+ ),
+ migrations.CreateModel(
+ name='SearchTestChild',
+ fields=[
+ ('searchtest_ptr', models.OneToOneField(primary_key=True, serialize=False, parent_link=True, to='searchtests.SearchTest', auto_created=True)),
+ ('subtitle', models.CharField(null=True, max_length=255, blank=True)),
+ ('extra_content', models.TextField()),
+ ],
+ options={
+ },
+ bases=('searchtests.searchtest',),
+ ),
+ ]
diff --git a/wagtail/tests/search/migrations/__init__.py b/wagtail/tests/search/migrations/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/wagtail/tests/search/models.py b/wagtail/tests/search/models.py
new file mode 100644
index 000000000..d5f646576
--- /dev/null
+++ b/wagtail/tests/search/models.py
@@ -0,0 +1,54 @@
+from django.db import models
+
+from wagtail.wagtailsearch import index
+
+
+class SearchTest(models.Model, index.Indexed):
+ title = models.CharField(max_length=255)
+ content = models.TextField()
+ live = models.BooleanField(default=False)
+ published_date = models.DateField(null=True)
+
+ search_fields = [
+ index.SearchField('title', partial_match=True),
+ index.SearchField('content'),
+ index.SearchField('callable_indexed_field'),
+ index.FilterField('title'),
+ index.FilterField('live'),
+ index.FilterField('published_date'),
+ ]
+
+ def callable_indexed_field(self):
+ return "Callable"
+
+ @classmethod
+ def get_indexed_objects(cls):
+ indexed_objects = super(SearchTest, cls).get_indexed_objects()
+
+ # Exclude SearchTests that have a SearchTestChild to stop update_index creating duplicates
+ if cls is SearchTest:
+ indexed_objects = indexed_objects.exclude(
+ id__in=SearchTestChild.objects.all().values_list('searchtest_ptr_id', flat=True)
+ )
+
+ # Exclude SearchTests that have the title "Don't index me!"
+ indexed_objects = indexed_objects.exclude(title="Don't index me!")
+
+ return indexed_objects
+
+ def get_indexed_instance(self):
+ # Check if there is a SearchTestChild that descends from this
+ child = SearchTestChild.objects.filter(searchtest_ptr_id=self.id).first()
+
+ # Return the child if there is one, otherwise return self
+ return child or self
+
+
+class SearchTestChild(SearchTest):
+ subtitle = models.CharField(max_length=255, null=True, blank=True)
+ extra_content = models.TextField()
+
+ search_fields = SearchTest.search_fields + [
+ index.SearchField('subtitle', partial_match=True),
+ index.SearchField('extra_content'),
+ ]
diff --git a/wagtail/tests/settings.py b/wagtail/tests/settings.py
index 3366af818..92b058af0 100644
--- a/wagtail/tests/settings.py
+++ b/wagtail/tests/settings.py
@@ -76,7 +76,12 @@ INSTALLED_APPS = (
'wagtail.contrib.wagtailsitemaps',
'wagtail.contrib.wagtailroutablepage',
'wagtail.contrib.wagtailfrontendcache',
- 'wagtail.tests',
+ 'wagtail.tests.testapp',
+ 'wagtail.tests.demosite',
+ 'wagtail.tests.customuser',
+ 'wagtail.tests.snippets',
+ 'wagtail.tests.routablepage',
+ 'wagtail.tests.search',
# Install wagtailredirects with its appconfig
# Theres nothing special about wagtailredirects, we just need to have one
@@ -110,7 +115,7 @@ WAGTAILSEARCH_BACKENDS = {
}
}
-AUTH_USER_MODEL = 'tests.CustomUser'
+AUTH_USER_MODEL = 'customuser.CustomUser'
try:
# Only add Elasticsearch backend if the elasticsearch-py library is installed
diff --git a/wagtail/tests/snippets/__init__.py b/wagtail/tests/snippets/__init__.py
new file mode 100644
index 000000000..96bbbaa54
--- /dev/null
+++ b/wagtail/tests/snippets/__init__.py
@@ -0,0 +1 @@
+default_app_config = 'wagtail.tests.snippets.apps.WagtailSnippetsTestsAppConfig'
diff --git a/wagtail/tests/snippets/apps.py b/wagtail/tests/snippets/apps.py
new file mode 100644
index 000000000..26004ec2b
--- /dev/null
+++ b/wagtail/tests/snippets/apps.py
@@ -0,0 +1,7 @@
+from django.apps import AppConfig
+
+
+class WagtailSnippetsTestsAppConfig(AppConfig):
+ name = 'wagtail.tests.snippets'
+ label = 'snippetstests'
+ verbose_name = "Wagtail snippets tests"
diff --git a/wagtail/tests/snippets/migrations/0001_initial.py b/wagtail/tests/snippets/migrations/0001_initial.py
new file mode 100644
index 000000000..b348bd2f5
--- /dev/null
+++ b/wagtail/tests/snippets/migrations/0001_initial.py
@@ -0,0 +1,51 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='AlphaSnippet',
+ fields=[
+ ('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)),
+ ('text', models.CharField(max_length=255)),
+ ],
+ options={
+ },
+ bases=(models.Model,),
+ ),
+ migrations.CreateModel(
+ name='RegisterDecorator',
+ fields=[
+ ('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)),
+ ],
+ options={
+ },
+ bases=(models.Model,),
+ ),
+ migrations.CreateModel(
+ name='RegisterFunction',
+ fields=[
+ ('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)),
+ ],
+ options={
+ },
+ bases=(models.Model,),
+ ),
+ migrations.CreateModel(
+ name='ZuluSnippet',
+ fields=[
+ ('id', models.AutoField(serialize=False, verbose_name='ID', auto_created=True, primary_key=True)),
+ ('text', models.CharField(max_length=255)),
+ ],
+ options={
+ },
+ bases=(models.Model,),
+ ),
+ ]
diff --git a/wagtail/tests/snippets/migrations/__init__.py b/wagtail/tests/snippets/migrations/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/wagtail/tests/snippets/models.py b/wagtail/tests/snippets/models.py
new file mode 100644
index 000000000..c3b9512a0
--- /dev/null
+++ b/wagtail/tests/snippets/models.py
@@ -0,0 +1,39 @@
+from django.db import models
+from django.utils.encoding import python_2_unicode_compatible
+
+from wagtail.wagtailsnippets.models import register_snippet
+
+
+# AlphaSnippet and ZuluSnippet are for testing ordering of
+# snippets when registering. They are named as such to ensure
+# thier ordering is clear. They are registered during testing
+# to ensure specific [in]correct register ordering
+
+# AlphaSnippet is registered during TestSnippetOrdering
+@python_2_unicode_compatible
+class AlphaSnippet(models.Model):
+ text = models.CharField(max_length=255)
+
+ def __str__(self):
+ return self.text
+
+
+# ZuluSnippet is registered during TestSnippetOrdering
+@python_2_unicode_compatible
+class ZuluSnippet(models.Model):
+ text = models.CharField(max_length=255)
+
+ def __str__(self):
+ return self.text
+
+
+# Register model as snippet using register_snippet as both a function and a decorator
+
+class RegisterFunction(models.Model):
+ pass
+register_snippet(RegisterFunction)
+
+@register_snippet
+class RegisterDecorator(models.Model):
+ pass
+
diff --git a/wagtail/tests/templates/tests/event_index.html b/wagtail/tests/templates/tests/event_index.html
deleted file mode 100644
index dc07020b2..000000000
--- a/wagtail/tests/templates/tests/event_index.html
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
- {{ self.title }}
-
-
- {{ self.title }}
- {% include "tests/includes/event_listing.html" %}
-
-
diff --git a/wagtail/tests/templates/tests/event_page.html b/wagtail/tests/templates/tests/event_page.html
deleted file mode 100644
index a3ccaa718..000000000
--- a/wagtail/tests/templates/tests/event_page.html
+++ /dev/null
@@ -1,17 +0,0 @@
-{% load wagtailcore_tags wagtailimages_tags %}
-
-
-
-
- Event: {{ self.title }}
-
-
- {{ self.title }}
- Event
- {% if self.feed_image %}
- {% image self.feed_image width-200 class="feed-image" %}
- {% endif %}
- {{ self.body|richtext }}
- Back to events index
-
-
diff --git a/wagtail/tests/templates/tests/event_page_password_required.html b/wagtail/tests/templates/tests/event_page_password_required.html
deleted file mode 100644
index e58d740ad..000000000
--- a/wagtail/tests/templates/tests/event_page_password_required.html
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
- {{ self.title }}
-
-
- {{ self.title }}
- This event is invitation only. Please enter your password to see the details.
-
-
-
diff --git a/wagtail/tests/templates/tests/form_page.html b/wagtail/tests/templates/tests/form_page.html
deleted file mode 100644
index d908c60a2..000000000
--- a/wagtail/tests/templates/tests/form_page.html
+++ /dev/null
@@ -1,16 +0,0 @@
-{% load wagtailcore_tags %}
-
-
-
-
- {{ self.title }}
-
-
- {{ self.title }}
-
-
-
diff --git a/wagtail/tests/templates/tests/form_page_landing.html b/wagtail/tests/templates/tests/form_page_landing.html
deleted file mode 100644
index d9a6369d4..000000000
--- a/wagtail/tests/templates/tests/form_page_landing.html
+++ /dev/null
@@ -1,12 +0,0 @@
-{% load wagtailcore_tags %}
-
-
-
-
- {{ self.title }}
-
-
- {{ self.title }}
- Thank you for your feedback.
-
-
diff --git a/wagtail/tests/templates/tests/simple_page.html b/wagtail/tests/templates/tests/simple_page.html
deleted file mode 100644
index 1f3593514..000000000
--- a/wagtail/tests/templates/tests/simple_page.html
+++ /dev/null
@@ -1,12 +0,0 @@
-{% load wagtailcore_tags %}
-
-
-
-
- {{ self.title }}
-
-
- {{ self.title }}
- Simple page
-
-
diff --git a/wagtail/tests/testapp/__init__.py b/wagtail/tests/testapp/__init__.py
new file mode 100644
index 000000000..accd0aff7
--- /dev/null
+++ b/wagtail/tests/testapp/__init__.py
@@ -0,0 +1 @@
+default_app_config = 'wagtail.tests.testapp.apps.WagtailTestsAppConfig'
diff --git a/wagtail/tests/testapp/apps.py b/wagtail/tests/testapp/apps.py
new file mode 100644
index 000000000..8dedd7f25
--- /dev/null
+++ b/wagtail/tests/testapp/apps.py
@@ -0,0 +1,7 @@
+from django.apps import AppConfig
+
+
+class WagtailTestsAppConfig(AppConfig):
+ name = 'wagtail.tests.testapp'
+ label = 'tests'
+ verbose_name = "Wagtail tests"
diff --git a/wagtail/tests/fixtures/test.json b/wagtail/tests/testapp/fixtures/test.json
similarity index 98%
rename from wagtail/tests/fixtures/test.json
rename to wagtail/tests/testapp/fixtures/test.json
index de8b1e27e..665006443 100644
--- a/wagtail/tests/fixtures/test.json
+++ b/wagtail/tests/testapp/fixtures/test.json
@@ -461,7 +461,7 @@
},
{
"pk": 1,
- "model": "tests.customuser",
+ "model": "customuser.customuser",
"fields": {
"username": "superuser",
"first_name": "",
@@ -478,7 +478,7 @@
},
{
"pk": 2,
- "model": "tests.customuser",
+ "model": "customuser.customuser",
"fields": {
"username": "eventeditor",
"first_name": "",
@@ -496,7 +496,7 @@
},
{
"pk": 3,
- "model": "tests.customuser",
+ "model": "customuser.customuser",
"fields": {
"username": "eventmoderator",
"first_name": "",
@@ -514,7 +514,7 @@
},
{
"pk": 4,
- "model": "tests.customuser",
+ "model": "customuser.customuser",
"fields": {
"username": "inactiveuser",
"first_name": "",
@@ -532,7 +532,7 @@
},
{
"pk": 5,
- "model": "tests.customuser",
+ "model": "customuser.customuser",
"fields": {
"username": "siteeditor",
"first_name": "",
@@ -550,7 +550,7 @@
},
{
"pk": 6,
- "model": "tests.customuser",
+ "model": "customuser.customuser",
"fields": {
"username": "admin_only_user",
"first_name": "",
diff --git a/wagtail/tests/migrations/0002_auto_20140827_0908.py b/wagtail/tests/testapp/migrations/0001_initial.py
similarity index 54%
rename from wagtail/tests/migrations/0002_auto_20140827_0908.py
rename to wagtail/tests/testapp/migrations/0001_initial.py
index 66c85ffb0..0c3af9b25 100644
--- a/wagtail/tests/migrations/0002_auto_20140827_0908.py
+++ b/wagtail/tests/testapp/migrations/0001_initial.py
@@ -3,29 +3,31 @@ from __future__ import unicode_literals
from django.db import models, migrations
import django.db.models.deletion
-import modelcluster.fields
-import wagtail.contrib.wagtailroutablepage.models
-import wagtail.wagtailcore.fields
-import wagtail.wagtailsearch.index
+from django.conf import settings
import modelcluster.tags
+import wagtail.wagtailimages.models
+import wagtail.wagtailadmin.taggable
+import modelcluster.fields
+import wagtail.wagtailcore.fields
+import taggit.managers
class Migration(migrations.Migration):
dependencies = [
- ('wagtailcore', '0002_initial_data'),
+ ('wagtailcore', '0013_update_golive_expire_help_text'),
('wagtaildocs', '0002_initial_data'),
('taggit', '0001_initial'),
- ('wagtailimages', '0002_initial_data'),
- ('tests', '0001_initial'),
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ('wagtailimages', '0005_make_filter_spec_unique'),
]
operations = [
migrations.CreateModel(
name='Advert',
fields=[
- ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
- ('url', models.URLField(null=True, blank=True)),
+ ('id', models.AutoField(serialize=False, auto_created=True, verbose_name='ID', primary_key=True)),
+ ('url', models.URLField(blank=True, null=True)),
('text', models.CharField(max_length=255)),
],
options={
@@ -35,27 +37,18 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='AdvertPlacement',
fields=[
- ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
+ ('id', models.AutoField(serialize=False, auto_created=True, verbose_name='ID', primary_key=True)),
+ ('colour', models.CharField(max_length=255)),
('advert', models.ForeignKey(to='tests.Advert', related_name='+')),
],
options={
},
bases=(models.Model,),
),
- migrations.CreateModel(
- name='AlphaSnippet',
- fields=[
- ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
- ('text', models.CharField(max_length=255)),
- ],
- options={
- },
- bases=(models.Model,),
- ),
migrations.CreateModel(
name='BusinessChild',
fields=[
- ('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)),
+ ('page_ptr', models.OneToOneField(parent_link=True, primary_key=True, to='wagtailcore.Page', auto_created=True, serialize=False)),
],
options={
'abstract': False,
@@ -65,7 +58,7 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='BusinessIndex',
fields=[
- ('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)),
+ ('page_ptr', models.OneToOneField(parent_link=True, primary_key=True, to='wagtailcore.Page', auto_created=True, serialize=False)),
],
options={
'abstract': False,
@@ -75,17 +68,63 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='BusinessSubIndex',
fields=[
- ('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)),
+ ('page_ptr', models.OneToOneField(parent_link=True, primary_key=True, to='wagtailcore.Page', auto_created=True, serialize=False)),
],
options={
'abstract': False,
},
bases=('wagtailcore.page',),
),
+ migrations.CreateModel(
+ name='CustomImageWithAdminFormFields',
+ fields=[
+ ('id', models.AutoField(serialize=False, auto_created=True, verbose_name='ID', primary_key=True)),
+ ('title', models.CharField(max_length=255, verbose_name='Title')),
+ ('file', models.ImageField(width_field='width', height_field='height', upload_to=wagtail.wagtailimages.models.get_upload_to, verbose_name='File')),
+ ('width', models.IntegerField(editable=False)),
+ ('height', models.IntegerField(editable=False)),
+ ('created_at', models.DateTimeField(auto_now_add=True)),
+ ('focal_point_x', models.PositiveIntegerField(blank=True, null=True)),
+ ('focal_point_y', models.PositiveIntegerField(blank=True, null=True)),
+ ('focal_point_width', models.PositiveIntegerField(blank=True, null=True)),
+ ('focal_point_height', models.PositiveIntegerField(blank=True, null=True)),
+ ('caption', models.CharField(max_length=255)),
+ ('not_editable_field', models.CharField(max_length=255)),
+ ('tags', taggit.managers.TaggableManager(verbose_name='Tags', to='taggit.Tag', blank=True, through='taggit.TaggedItem', help_text=None)),
+ ('uploaded_by_user', models.ForeignKey(null=True, blank=True, to=settings.AUTH_USER_MODEL, editable=False)),
+ ],
+ options={
+ 'abstract': False,
+ },
+ bases=(models.Model, wagtail.wagtailadmin.taggable.TagSearchable),
+ ),
+ migrations.CreateModel(
+ name='CustomImageWithoutAdminFormFields',
+ fields=[
+ ('id', models.AutoField(serialize=False, auto_created=True, verbose_name='ID', primary_key=True)),
+ ('title', models.CharField(max_length=255, verbose_name='Title')),
+ ('file', models.ImageField(width_field='width', height_field='height', upload_to=wagtail.wagtailimages.models.get_upload_to, verbose_name='File')),
+ ('width', models.IntegerField(editable=False)),
+ ('height', models.IntegerField(editable=False)),
+ ('created_at', models.DateTimeField(auto_now_add=True)),
+ ('focal_point_x', models.PositiveIntegerField(blank=True, null=True)),
+ ('focal_point_y', models.PositiveIntegerField(blank=True, null=True)),
+ ('focal_point_width', models.PositiveIntegerField(blank=True, null=True)),
+ ('focal_point_height', models.PositiveIntegerField(blank=True, null=True)),
+ ('caption', models.CharField(max_length=255)),
+ ('not_editable_field', models.CharField(max_length=255)),
+ ('tags', taggit.managers.TaggableManager(verbose_name='Tags', to='taggit.Tag', blank=True, through='taggit.TaggedItem', help_text=None)),
+ ('uploaded_by_user', models.ForeignKey(null=True, blank=True, to=settings.AUTH_USER_MODEL, editable=False)),
+ ],
+ options={
+ 'abstract': False,
+ },
+ bases=(models.Model, wagtail.wagtailadmin.taggable.TagSearchable),
+ ),
migrations.CreateModel(
name='EventIndex',
fields=[
- ('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)),
+ ('page_ptr', models.OneToOneField(parent_link=True, primary_key=True, to='wagtailcore.Page', auto_created=True, serialize=False)),
('intro', wagtail.wagtailcore.fields.RichTextField(blank=True)),
],
options={
@@ -96,17 +135,17 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='EventPage',
fields=[
- ('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)),
- ('date_from', models.DateField(null=True, verbose_name='Start date')),
- ('date_to', models.DateField(null=True, help_text='Not required if event is on a single day', blank=True, verbose_name='End date')),
- ('time_from', models.TimeField(null=True, blank=True, verbose_name='Start time')),
- ('time_to', models.TimeField(null=True, blank=True, verbose_name='End time')),
+ ('page_ptr', models.OneToOneField(parent_link=True, primary_key=True, to='wagtailcore.Page', auto_created=True, serialize=False)),
+ ('date_from', models.DateField(verbose_name='Start date', null=True)),
+ ('date_to', models.DateField(blank=True, help_text='Not required if event is on a single day', verbose_name='End date', null=True)),
+ ('time_from', models.TimeField(blank=True, verbose_name='Start time', null=True)),
+ ('time_to', models.TimeField(blank=True, verbose_name='End time', null=True)),
('audience', models.CharField(choices=[('public', 'Public'), ('private', 'Private')], max_length=255)),
('location', models.CharField(max_length=255)),
('body', wagtail.wagtailcore.fields.RichTextField(blank=True)),
('cost', models.CharField(max_length=255)),
('signup_link', models.URLField(blank=True)),
- ('feed_image', models.ForeignKey(related_name='+', blank=True, to='wagtailimages.Image', on_delete=django.db.models.deletion.SET_NULL, null=True)),
+ ('feed_image', models.ForeignKey(to='wagtailimages.Image', null=True, related_name='+', blank=True, on_delete=django.db.models.deletion.SET_NULL)),
],
options={
'abstract': False,
@@ -116,74 +155,84 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='EventPageCarouselItem',
fields=[
- ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
- ('sort_order', models.IntegerField(null=True, blank=True, editable=False)),
+ ('id', models.AutoField(serialize=False, auto_created=True, verbose_name='ID', primary_key=True)),
+ ('sort_order', models.IntegerField(editable=False, null=True, blank=True)),
('link_external', models.URLField(blank=True, verbose_name='External link')),
('embed_url', models.URLField(blank=True, verbose_name='Embed URL')),
('caption', models.CharField(blank=True, max_length=255)),
- ('image', models.ForeignKey(related_name='+', blank=True, to='wagtailimages.Image', on_delete=django.db.models.deletion.SET_NULL, null=True)),
- ('link_document', models.ForeignKey(related_name='+', blank=True, to='wagtaildocs.Document', null=True)),
+ ('image', models.ForeignKey(to='wagtailimages.Image', null=True, related_name='+', blank=True, on_delete=django.db.models.deletion.SET_NULL)),
+ ('link_document', models.ForeignKey(to='wagtaildocs.Document', null=True, related_name='+', blank=True)),
],
options={
- 'abstract': False,
'ordering': ['sort_order'],
+ 'abstract': False,
+ },
+ bases=(models.Model,),
+ ),
+ migrations.CreateModel(
+ name='EventPageChooserModel',
+ fields=[
+ ('id', models.AutoField(serialize=False, auto_created=True, verbose_name='ID', primary_key=True)),
+ ('page', models.ForeignKey(to='tests.EventPage', help_text='more help text')),
+ ],
+ options={
},
bases=(models.Model,),
),
migrations.CreateModel(
name='EventPageRelatedLink',
fields=[
- ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
- ('sort_order', models.IntegerField(null=True, blank=True, editable=False)),
+ ('id', models.AutoField(serialize=False, auto_created=True, verbose_name='ID', primary_key=True)),
+ ('sort_order', models.IntegerField(editable=False, null=True, blank=True)),
('link_external', models.URLField(blank=True, verbose_name='External link')),
('title', models.CharField(help_text='Link title', max_length=255)),
- ('link_document', models.ForeignKey(related_name='+', blank=True, to='wagtaildocs.Document', null=True)),
+ ('link_document', models.ForeignKey(to='wagtaildocs.Document', null=True, related_name='+', blank=True)),
],
options={
- 'abstract': False,
'ordering': ['sort_order'],
+ 'abstract': False,
},
bases=(models.Model,),
),
migrations.CreateModel(
name='EventPageSpeaker',
fields=[
- ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
- ('sort_order', models.IntegerField(null=True, blank=True, editable=False)),
+ ('id', models.AutoField(serialize=False, auto_created=True, verbose_name='ID', primary_key=True)),
+ ('sort_order', models.IntegerField(editable=False, null=True, blank=True)),
('link_external', models.URLField(blank=True, verbose_name='External link')),
- ('first_name', models.CharField(blank=True, verbose_name='Name', max_length=255)),
- ('last_name', models.CharField(blank=True, verbose_name='Surname', max_length=255)),
- ('image', models.ForeignKey(related_name='+', blank=True, to='wagtailimages.Image', on_delete=django.db.models.deletion.SET_NULL, null=True)),
- ('link_document', models.ForeignKey(related_name='+', blank=True, to='wagtaildocs.Document', null=True)),
+ ('first_name', models.CharField(blank=True, max_length=255, verbose_name='Name')),
+ ('last_name', models.CharField(blank=True, max_length=255, verbose_name='Surname')),
+ ('image', models.ForeignKey(to='wagtailimages.Image', null=True, related_name='+', blank=True, on_delete=django.db.models.deletion.SET_NULL)),
+ ('link_document', models.ForeignKey(to='wagtaildocs.Document', null=True, related_name='+', blank=True)),
],
options={
- 'abstract': False,
'ordering': ['sort_order'],
+ 'abstract': False,
},
bases=(models.Model,),
),
migrations.CreateModel(
name='FormField',
fields=[
- ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
- ('sort_order', models.IntegerField(null=True, blank=True, editable=False)),
+ ('id', models.AutoField(serialize=False, auto_created=True, verbose_name='ID', primary_key=True)),
+ ('sort_order', models.IntegerField(editable=False, null=True, blank=True)),
('label', models.CharField(help_text='The label of the form field', max_length=255)),
('field_type', models.CharField(choices=[('singleline', 'Single line text'), ('multiline', 'Multi-line text'), ('email', 'Email'), ('number', 'Number'), ('url', 'URL'), ('checkbox', 'Checkbox'), ('checkboxes', 'Checkboxes'), ('dropdown', 'Drop down'), ('radio', 'Radio buttons'), ('date', 'Date'), ('datetime', 'Date/time')], max_length=16)),
('required', models.BooleanField(default=True)),
- ('choices', models.CharField(blank=True, help_text='Comma seperated list of choices. Only applicable in checkboxes, radio and dropdown.', max_length=512)),
- ('default_value', models.CharField(blank=True, help_text='Default value. Comma seperated values supported for checkboxes.', max_length=255)),
+ ('choices', models.CharField(blank=True, help_text='Comma separated list of choices. Only applicable in checkboxes, radio and dropdown.', max_length=512)),
+ ('default_value', models.CharField(blank=True, help_text='Default value. Comma separated values supported for checkboxes.', max_length=255)),
('help_text', models.CharField(blank=True, max_length=255)),
],
options={
- 'abstract': False,
'ordering': ['sort_order'],
+ 'abstract': False,
},
bases=(models.Model,),
),
migrations.CreateModel(
name='FormPage',
fields=[
- ('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)),
+ ('page_ptr', models.OneToOneField(parent_link=True, primary_key=True, to='wagtailcore.Page', auto_created=True, serialize=False)),
('to_address', models.CharField(blank=True, help_text='Optional - form submissions will be emailed to this address', max_length=255)),
('from_address', models.CharField(blank=True, max_length=255)),
('subject', models.CharField(blank=True, max_length=255)),
@@ -193,10 +242,19 @@ class Migration(migrations.Migration):
},
bases=('wagtailcore.page',),
),
+ migrations.CreateModel(
+ name='PageChooserModel',
+ fields=[
+ ('id', models.AutoField(serialize=False, auto_created=True, verbose_name='ID', primary_key=True)),
+ ],
+ options={
+ },
+ bases=(models.Model,),
+ ),
migrations.CreateModel(
name='PageWithOldStyleRouteMethod',
fields=[
- ('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)),
+ ('page_ptr', models.OneToOneField(parent_link=True, primary_key=True, to='wagtailcore.Page', auto_created=True, serialize=False)),
('content', models.TextField()),
],
options={
@@ -204,62 +262,10 @@ class Migration(migrations.Migration):
},
bases=('wagtailcore.page',),
),
- migrations.CreateModel(
- name='RoutablePageTest',
- fields=[
- ('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)),
- ],
- options={
- 'abstract': False,
- },
- bases=(wagtail.contrib.wagtailroutablepage.models.RoutablePageMixin, 'wagtailcore.page'),
- ),
- migrations.CreateModel(
- name='SearchTest',
- fields=[
- ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
- ('title', models.CharField(max_length=255)),
- ('content', models.TextField()),
- ('live', models.BooleanField(default=False)),
- ('published_date', models.DateField(null=True)),
- ],
- options={
- },
- bases=(models.Model, wagtail.wagtailsearch.index.Indexed),
- ),
- migrations.CreateModel(
- name='SearchTestChild',
- fields=[
- ('searchtest_ptr', models.OneToOneField(parent_link=True, to='tests.SearchTest', serialize=False, auto_created=True, primary_key=True)),
- ('subtitle', models.CharField(null=True, blank=True, max_length=255)),
- ('extra_content', models.TextField()),
- ],
- options={
- },
- bases=('tests.searchtest',),
- ),
- migrations.CreateModel(
- name='SearchTestOldConfig',
- fields=[
- ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
- ],
- options={
- },
- bases=(models.Model, wagtail.wagtailsearch.index.Indexed),
- ),
- migrations.CreateModel(
- name='SearchTestOldConfigList',
- fields=[
- ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
- ],
- options={
- },
- bases=(models.Model, wagtail.wagtailsearch.index.Indexed),
- ),
migrations.CreateModel(
name='SimplePage',
fields=[
- ('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)),
+ ('page_ptr', models.OneToOneField(parent_link=True, primary_key=True, to='wagtailcore.Page', auto_created=True, serialize=False)),
('content', models.TextField()),
],
options={
@@ -267,10 +273,20 @@ class Migration(migrations.Migration):
},
bases=('wagtailcore.page',),
),
+ migrations.CreateModel(
+ name='SnippetChooserModel',
+ fields=[
+ ('id', models.AutoField(serialize=False, auto_created=True, verbose_name='ID', primary_key=True)),
+ ('advert', models.ForeignKey(to='tests.Advert', help_text='help text')),
+ ],
+ options={
+ },
+ bases=(models.Model,),
+ ),
migrations.CreateModel(
name='StandardChild',
fields=[
- ('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)),
+ ('page_ptr', models.OneToOneField(parent_link=True, primary_key=True, to='wagtailcore.Page', auto_created=True, serialize=False)),
],
options={
'abstract': False,
@@ -280,7 +296,7 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='StandardIndex',
fields=[
- ('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)),
+ ('page_ptr', models.OneToOneField(parent_link=True, primary_key=True, to='wagtailcore.Page', auto_created=True, serialize=False)),
],
options={
'abstract': False,
@@ -290,7 +306,7 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='TaggedPage',
fields=[
- ('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)),
+ ('page_ptr', models.OneToOneField(parent_link=True, primary_key=True, to='wagtailcore.Page', auto_created=True, serialize=False)),
],
options={
'abstract': False,
@@ -300,7 +316,7 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='TaggedPageTag',
fields=[
- ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
+ ('id', models.AutoField(serialize=False, auto_created=True, verbose_name='ID', primary_key=True)),
('content_object', modelcluster.fields.ParentalKey(to='tests.TaggedPage', related_name='tagged_items')),
('tag', models.ForeignKey(to='taggit.Tag', related_name='tests_taggedpagetag_items')),
],
@@ -309,20 +325,16 @@ class Migration(migrations.Migration):
},
bases=(models.Model,),
),
- migrations.CreateModel(
- name='ZuluSnippet',
- fields=[
- ('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
- ('text', models.CharField(max_length=255)),
- ],
- options={
- },
- bases=(models.Model,),
- ),
migrations.AddField(
model_name='taggedpage',
name='tags',
- field=modelcluster.tags.ClusterTaggableManager(through='tests.TaggedPageTag', blank=True, verbose_name='Tags', to='taggit.Tag', help_text='A comma-separated list of tags.'),
+ field=modelcluster.tags.ClusterTaggableManager(verbose_name='Tags', to='taggit.Tag', blank=True, through='tests.TaggedPageTag', help_text='A comma-separated list of tags.'),
+ preserve_default=True,
+ ),
+ migrations.AddField(
+ model_name='pagechoosermodel',
+ name='page',
+ field=models.ForeignKey(to='wagtailcore.Page', help_text='help text'),
preserve_default=True,
),
migrations.AddField(
@@ -334,7 +346,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='eventpagespeaker',
name='link_page',
- field=models.ForeignKey(related_name='+', blank=True, to='wagtailcore.Page', null=True),
+ field=models.ForeignKey(to='wagtailcore.Page', null=True, related_name='+', blank=True),
preserve_default=True,
),
migrations.AddField(
@@ -346,7 +358,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='eventpagerelatedlink',
name='link_page',
- field=models.ForeignKey(related_name='+', blank=True, to='wagtailcore.Page', null=True),
+ field=models.ForeignKey(to='wagtailcore.Page', null=True, related_name='+', blank=True),
preserve_default=True,
),
migrations.AddField(
@@ -358,7 +370,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='eventpagecarouselitem',
name='link_page',
- field=models.ForeignKey(related_name='+', blank=True, to='wagtailcore.Page', null=True),
+ field=models.ForeignKey(to='wagtailcore.Page', null=True, related_name='+', blank=True),
preserve_default=True,
),
migrations.AddField(
@@ -373,14 +385,4 @@ class Migration(migrations.Migration):
field=modelcluster.fields.ParentalKey(to='wagtailcore.Page', related_name='advert_placements'),
preserve_default=True,
),
- migrations.AlterField(
- model_name='customuser',
- name='groups',
- field=models.ManyToManyField(related_name='user_set', blank=True, verbose_name='groups', to='auth.Group', related_query_name='user', help_text='The groups this user belongs to. A user will get all permissions granted to each of his/her group.'),
- ),
- migrations.AlterField(
- model_name='customuser',
- name='user_permissions',
- field=models.ManyToManyField(related_name='user_set', blank=True, verbose_name='user permissions', to='auth.Permission', related_query_name='user', help_text='Specific permissions for this user.'),
- ),
]
diff --git a/wagtail/tests/testapp/migrations/__init__.py b/wagtail/tests/testapp/migrations/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/wagtail/tests/models.py b/wagtail/tests/testapp/models.py
similarity index 68%
rename from wagtail/tests/models.py
rename to wagtail/tests/testapp/models.py
index bb6f5f007..628997b00 100644
--- a/wagtail/tests/models.py
+++ b/wagtail/tests/testapp/models.py
@@ -2,10 +2,7 @@ from __future__ import unicode_literals
from django.db import models
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
-from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager
from django.utils.encoding import python_2_unicode_compatible
-from django.conf.urls import url
-from django.http import HttpResponse
from taggit.models import TaggedItemBase
@@ -17,11 +14,10 @@ from wagtail.wagtailcore.fields import RichTextField
from wagtail.wagtailadmin.edit_handlers import FieldPanel, MultiFieldPanel, InlinePanel, PageChooserPanel, TabbedInterface, ObjectList
from wagtail.wagtailimages.edit_handlers import ImageChooserPanel
from wagtail.wagtaildocs.edit_handlers import DocumentChooserPanel
-from wagtail.wagtailforms.models import AbstractEmailForm, AbstractFormField
from wagtail.wagtailsnippets.models import register_snippet
+from wagtail.wagtailforms.models import AbstractEmailForm, AbstractFormField
from wagtail.wagtailsnippets.edit_handlers import SnippetChooserPanel
from wagtail.wagtailsearch import index
-from wagtail.contrib.wagtailroutablepage.models import RoutablePage
from wagtail.wagtailimages.models import AbstractImage, Image
@@ -39,50 +35,6 @@ COMMON_PANELS = (
)
-class CustomUserManager(BaseUserManager):
- def _create_user(self, username, email, password,
- is_staff, is_superuser, **extra_fields):
- """
- Creates and saves a User with the given username, email and password.
- """
- if not username:
- raise ValueError('The given username must be set')
- email = self.normalize_email(email)
- user = self.model(username=username, email=email,
- is_staff=is_staff, is_active=True,
- is_superuser=is_superuser, **extra_fields)
- user.set_password(password)
- user.save(using=self._db)
- return user
-
- def create_user(self, username, email=None, password=None, **extra_fields):
- return self._create_user(username, email, password, False, False,
- **extra_fields)
-
- def create_superuser(self, username, email, password, **extra_fields):
- return self._create_user(username, email, password, True, True,
- **extra_fields)
-
-
-class CustomUser(AbstractBaseUser, PermissionsMixin):
- username = models.CharField(max_length=100, unique=True)
- email = models.EmailField(max_length=255, blank=True)
- is_staff = models.BooleanField(default=True)
- is_active = models.BooleanField(default=True)
- first_name = models.CharField(max_length=50, blank=True)
- last_name = models.CharField(max_length=50, blank=True)
-
- USERNAME_FIELD = 'username'
-
- objects = CustomUserManager()
-
- def get_full_name(self):
- return self.first_name + ' ' + self.last_name
-
- def get_short_name(self):
- return self.first_name
-
-
# Link fields
class LinkFields(models.Model):
@@ -365,29 +317,6 @@ class Advert(models.Model):
register_snippet(Advert)
-# AlphaSnippet and ZuluSnippet are for testing ordering of
-# snippets when registering. They are named as such to ensure
-# thier ordering is clear. They are registered during testing
-# to ensure specific [in]correct register ordering
-
-# AlphaSnippet is registered during TestSnippetOrdering
-@python_2_unicode_compatible
-class AlphaSnippet(models.Model):
- text = models.CharField(max_length=255)
-
- def __str__(self):
- return self.text
-
-
-# ZuluSnippet is registered during TestSnippetOrdering
-@python_2_unicode_compatible
-class ZuluSnippet(models.Model):
- text = models.CharField(max_length=255)
-
- def __str__(self):
- return self.text
-
-
class StandardIndex(Page):
""" Index for the site, not allowed to be placed anywhere """
parent_page_types = []
@@ -432,77 +361,6 @@ class BusinessChild(Page):
parent_page_types = ['tests.BusinessIndex', BusinessSubIndex]
-class SearchTest(models.Model, index.Indexed):
- title = models.CharField(max_length=255)
- content = models.TextField()
- live = models.BooleanField(default=False)
- published_date = models.DateField(null=True)
-
- search_fields = [
- index.SearchField('title', partial_match=True),
- index.SearchField('content'),
- index.SearchField('callable_indexed_field'),
- index.FilterField('title'),
- index.FilterField('live'),
- index.FilterField('published_date'),
- ]
-
- def callable_indexed_field(self):
- return "Callable"
-
- @classmethod
- def get_indexed_objects(cls):
- indexed_objects = super(SearchTest, cls).get_indexed_objects()
-
- # Exclude SearchTests that have a SearchTestChild to stop update_index creating duplicates
- if cls is SearchTest:
- indexed_objects = indexed_objects.exclude(
- id__in=SearchTestChild.objects.all().values_list('searchtest_ptr_id', flat=True)
- )
-
- # Exclude SearchTests that have the title "Don't index me!"
- indexed_objects = indexed_objects.exclude(title="Don't index me!")
-
- return indexed_objects
-
- def get_indexed_instance(self):
- # Check if there is a SearchTestChild that descends from this
- child = SearchTestChild.objects.filter(searchtest_ptr_id=self.id).first()
-
- # Return the child if there is one, otherwise return self
- return child or self
-
-class SearchTestChild(SearchTest):
- subtitle = models.CharField(max_length=255, null=True, blank=True)
- extra_content = models.TextField()
-
- search_fields = SearchTest.search_fields + [
- index.SearchField('subtitle', partial_match=True),
- index.SearchField('extra_content'),
- ]
-
-
-def routable_page_external_view(request, arg):
- return HttpResponse("EXTERNAL VIEW: " + arg)
-
-class RoutablePageTest(RoutablePage):
- subpage_urls = (
- url(r'^$', 'main', name='main'),
- url(r'^archive/year/(\d+)/$', 'archive_by_year', name='archive_by_year'),
- url(r'^archive/author/(?P.+)/$', 'archive_by_author', name='archive_by_author'),
- url(r'^external/(.+)/$', routable_page_external_view, name='external_view')
- )
-
- def archive_by_year(self, request, year):
- return HttpResponse("ARCHIVE BY YEAR: " + str(year))
-
- def archive_by_author(self, request, author_slug):
- return HttpResponse("ARCHIVE BY AUTHOR: " + author_slug)
-
- def main(self, request):
- return HttpResponse("MAIN VIEW")
-
-
class TaggedPageTag(TaggedItemBase):
content_object = ParentalKey('tests.TaggedPage', related_name='tagged_items')
@@ -530,17 +388,6 @@ class SnippetChooserModel(models.Model):
]
-# Register model as snippet using register_snippet as both a function and a decorator
-
-class RegisterFunction(models.Model):
- pass
-register_snippet(RegisterFunction)
-
-@register_snippet
-class RegisterDecorator(models.Model):
- pass
-
-
class CustomImageWithoutAdminFormFields(AbstractImage):
caption = models.CharField(max_length=255)
not_editable_field = models.CharField(max_length=255)
diff --git a/wagtail/tests/testapp/templates/tests/base.html b/wagtail/tests/testapp/templates/tests/base.html
new file mode 100644
index 000000000..636b5c588
--- /dev/null
+++ b/wagtail/tests/testapp/templates/tests/base.html
@@ -0,0 +1,13 @@
+{% load wagtailuserbar %}
+
+
+
+
+ {% block html_title %}{{ self.title }}{% endblock %}
+
+
+ {% wagtailuserbar %}
+ {{ self.title }}
+ {% block content %}{% endblock %}
+
+
diff --git a/wagtail/tests/testapp/templates/tests/business_child.html b/wagtail/tests/testapp/templates/tests/business_child.html
new file mode 100644
index 000000000..33e29f1c2
--- /dev/null
+++ b/wagtail/tests/testapp/templates/tests/business_child.html
@@ -0,0 +1,5 @@
+{% extends "tests/base.html" %}
+
+{% block content %}
+ Business Child
+{% endblock %}
diff --git a/wagtail/tests/testapp/templates/tests/event_index.html b/wagtail/tests/testapp/templates/tests/event_index.html
new file mode 100644
index 000000000..345aac9e0
--- /dev/null
+++ b/wagtail/tests/testapp/templates/tests/event_index.html
@@ -0,0 +1,5 @@
+{% extends "tests/base.html" %}
+
+{% block content %}
+ {% include "tests/includes/event_listing.html" %}
+{% endblock %}
diff --git a/wagtail/tests/testapp/templates/tests/event_page.html b/wagtail/tests/testapp/templates/tests/event_page.html
new file mode 100644
index 000000000..f2f486962
--- /dev/null
+++ b/wagtail/tests/testapp/templates/tests/event_page.html
@@ -0,0 +1,12 @@
+{% extends "tests/base.html" %}
+{% load wagtailcore_tags wagtailimages_tags %}
+
+{% block html_title %}Event: {{ self.title }}{% endblock %}
+{% block content %}
+ Event
+ {% if self.feed_image %}
+ {% image self.feed_image width-200 class="feed-image" %}
+ {% endif %}
+ {{ self.body|richtext }}
+ Back to events index
+{% endblock %}
diff --git a/wagtail/tests/testapp/templates/tests/event_page_password_required.html b/wagtail/tests/testapp/templates/tests/event_page_password_required.html
new file mode 100644
index 000000000..7311c7940
--- /dev/null
+++ b/wagtail/tests/testapp/templates/tests/event_page_password_required.html
@@ -0,0 +1,10 @@
+{% extends "tests/base.html" %}
+
+{% block content %}
+ This event is invitation only. Please enter your password to see the details.
+
+{% endblock %}
diff --git a/wagtail/tests/testapp/templates/tests/form_page.html b/wagtail/tests/testapp/templates/tests/form_page.html
new file mode 100644
index 000000000..f275ec80f
--- /dev/null
+++ b/wagtail/tests/testapp/templates/tests/form_page.html
@@ -0,0 +1,10 @@
+{% extends "tests/base.html" %}
+{% load wagtailcore_tags %}
+
+{% block content %}
+
+{% endblock %}
diff --git a/wagtail/tests/testapp/templates/tests/form_page_landing.html b/wagtail/tests/testapp/templates/tests/form_page_landing.html
new file mode 100644
index 000000000..9615c79d3
--- /dev/null
+++ b/wagtail/tests/testapp/templates/tests/form_page_landing.html
@@ -0,0 +1,5 @@
+{% extends "tests/base.html" %}
+
+{% block content %}
+ Thank you for your feedback.
+{% endblock %}
diff --git a/wagtail/tests/templates/tests/includes/event_listing.html b/wagtail/tests/testapp/templates/tests/includes/event_listing.html
similarity index 100%
rename from wagtail/tests/templates/tests/includes/event_listing.html
rename to wagtail/tests/testapp/templates/tests/includes/event_listing.html
diff --git a/wagtail/tests/testapp/templates/tests/simple_page.html b/wagtail/tests/testapp/templates/tests/simple_page.html
new file mode 100644
index 000000000..7a173c096
--- /dev/null
+++ b/wagtail/tests/testapp/templates/tests/simple_page.html
@@ -0,0 +1,5 @@
+{% extends "tests/base.html" %}
+
+{% block content %}
+ Simple page
+{% endblock %}
diff --git a/wagtail/tests/wagtail_hooks.py b/wagtail/tests/testapp/wagtail_hooks.py
similarity index 100%
rename from wagtail/tests/wagtail_hooks.py
rename to wagtail/tests/testapp/wagtail_hooks.py
diff --git a/wagtail/wagtailadmin/tasks.py b/wagtail/wagtailadmin/tasks.py
deleted file mode 100644
index 815971e46..000000000
--- a/wagtail/wagtailadmin/tasks.py
+++ /dev/null
@@ -1,101 +0,0 @@
-from django.template.loader import render_to_string
-from django.core.mail import send_mail
-from django.conf import settings
-from django.contrib.auth import get_user_model
-from django.db.models import Q
-
-from wagtail.wagtailcore.models import PageRevision, GroupPagePermission
-from wagtail.wagtailusers.models import UserProfile
-
-# The following will check to see if we can import task from celery -
-# if not then we definitely haven't installed it
-try:
- from celery.decorators import task
- NO_CELERY = False
-except:
- NO_CELERY = True
-
-
-# However, we could have installed celery for other projects. So we will also
-# check if we have defined the BROKER_URL setting. If not then definitely we
-# haven't configured it.
-if NO_CELERY or not hasattr(settings, 'BROKER_URL'):
- # So if we enter here we will define a different "task" decorator that
- # just returns the original function and sets its delay attribute to
- # point to the original function: This way, the send_notification
- # function will be actually called instead of the the
- # send_notification.delay()
- def task(f):
- f.delay=f
- return f
-
-def users_with_page_permission(page, permission_type, include_superusers=True):
- # Get user model
- User = get_user_model()
-
- # Find GroupPagePermission records of the given type that apply to this page or an ancestor
- ancestors_and_self = list(page.get_ancestors()) + [page]
- perm = GroupPagePermission.objects.filter(permission_type=permission_type, page__in=ancestors_and_self)
- q = Q(groups__page_permissions=perm)
-
- # Include superusers
- if include_superusers:
- q |= Q(is_superuser=True)
-
- return User.objects.filter(is_active=True).filter(q).distinct()
-
-
-@task
-def send_notification(page_revision_id, notification, excluded_user_id):
- # Get revision
- revision = PageRevision.objects.get(id=page_revision_id)
-
- # Get list of recipients
- if notification == 'submitted':
- # Get list of publishers
- recipients = users_with_page_permission(revision.page, 'publish')
- elif notification in ['rejected', 'approved']:
- # Get submitter
- recipients = [revision.user]
- else:
- return
-
- # Get list of email addresses
- email_addresses = [
- recipient.email for recipient in recipients
- if recipient.email and recipient.id != excluded_user_id and getattr(UserProfile.get_for_user(recipient), notification + '_notifications')
- ]
-
- # Return if there are no email addresses
- if not email_addresses:
- return
-
- # Get email subject and content
- template = 'wagtailadmin/notifications/' + notification + '.html'
- rendered_template = render_to_string(template, dict(revision=revision, settings=settings)).split('\n')
- email_subject = rendered_template[0]
- email_content = '\n'.join(rendered_template[1:])
-
- # Get from email
- if hasattr(settings, 'WAGTAILADMIN_NOTIFICATION_FROM_EMAIL'):
- from_email = settings.WAGTAILADMIN_NOTIFICATION_FROM_EMAIL
- elif hasattr(settings, 'DEFAULT_FROM_EMAIL'):
- from_email = settings.DEFAULT_FROM_EMAIL
- else:
- from_email = 'webmaster@localhost'
-
- # Send email
- send_mail(email_subject, email_content, from_email, email_addresses)
-
-
-@task
-def send_email_task(email_subject, email_content, email_addresses, from_email=None):
- if not from_email:
- if hasattr(settings, 'WAGTAILADMIN_NOTIFICATION_FROM_EMAIL'):
- from_email = settings.WAGTAILADMIN_NOTIFICATION_FROM_EMAIL
- elif hasattr(settings, 'DEFAULT_FROM_EMAIL'):
- from_email = settings.DEFAULT_FROM_EMAIL
- else:
- from_email = 'webmaster@localhost'
-
- send_mail(email_subject, email_content, from_email, email_addresses)
diff --git a/wagtail/wagtailadmin/templates/wagtailadmin/userbar/item_page_add.html b/wagtail/wagtailadmin/templates/wagtailadmin/userbar/item_page_add.html
index 45f0002e9..1a4d0a7f4 100644
--- a/wagtail/wagtailadmin/templates/wagtailadmin/userbar/item_page_add.html
+++ b/wagtail/wagtailadmin/templates/wagtailadmin/userbar/item_page_add.html
@@ -2,5 +2,5 @@
{% load i18n %}
{% block item_content %}
- {% trans 'Add' %}
-{% endblock %}
\ No newline at end of file
+ {% trans 'Add' %}
+{% endblock %}
diff --git a/wagtail/wagtailadmin/tests/test_edit_handlers.py b/wagtail/wagtailadmin/tests/test_edit_handlers.py
index 74128b3c5..8ff597d87 100644
--- a/wagtail/wagtailadmin/tests/test_edit_handlers.py
+++ b/wagtail/wagtailadmin/tests/test_edit_handlers.py
@@ -20,7 +20,7 @@ from wagtail.wagtailadmin.widgets import AdminPageChooser, AdminDateInput, Admin
from wagtail.wagtailimages.edit_handlers import ImageChooserPanel
from wagtail.wagtailcore.models import Page, Site
from wagtail.wagtailcore.fields import RichTextArea
-from wagtail.tests.models import PageChooserModel, EventPageChooserModel, EventPage, EventPageSpeaker, SimplePage
+from wagtail.tests.testapp.models import PageChooserModel, EventPageChooserModel, EventPage, EventPageSpeaker, SimplePage
from wagtail.tests.utils import WagtailTestUtils
from wagtail.utils.deprecation import RemovedInWagtail12Warning
diff --git a/wagtail/wagtailadmin/tests/test_page_chooser.py b/wagtail/wagtailadmin/tests/test_page_chooser.py
index 834acde8c..3d67cbfaa 100644
--- a/wagtail/wagtailadmin/tests/test_page_chooser.py
+++ b/wagtail/wagtailadmin/tests/test_page_chooser.py
@@ -2,7 +2,7 @@ from django.test import TestCase
from django.core.urlresolvers import reverse
from wagtail.wagtailcore.models import Page
-from wagtail.tests.models import SimplePage
+from wagtail.tests.testapp.models import SimplePage
from wagtail.tests.utils import WagtailTestUtils
diff --git a/wagtail/wagtailadmin/tests/test_pages_views.py b/wagtail/wagtailadmin/tests/test_pages_views.py
index 8bd3634a7..314a31aaf 100644
--- a/wagtail/wagtailadmin/tests/test_pages_views.py
+++ b/wagtail/wagtailadmin/tests/test_pages_views.py
@@ -11,7 +11,7 @@ from django.core.paginator import Paginator
from django.db.models.signals import pre_delete, post_delete
from django.utils import timezone
-from wagtail.tests.models import (
+from wagtail.tests.testapp.models import (
SimplePage, EventPage, EventPageCarouselItem,
StandardIndex, StandardChild,
BusinessIndex, BusinessChild, BusinessSubIndex,
diff --git a/wagtail/wagtailadmin/tests/test_privacy.py b/wagtail/wagtailadmin/tests/test_privacy.py
index e49b81e0a..bda4fbd8c 100644
--- a/wagtail/wagtailadmin/tests/test_privacy.py
+++ b/wagtail/wagtailadmin/tests/test_privacy.py
@@ -2,7 +2,7 @@ from django.test import TestCase
from django.core.urlresolvers import reverse
from wagtail.wagtailcore.models import Page, PageViewRestriction
-from wagtail.tests.models import SimplePage
+from wagtail.tests.testapp.models import SimplePage
from wagtail.tests.utils import WagtailTestUtils
diff --git a/wagtail/wagtailadmin/tests/test_userbar.py b/wagtail/wagtailadmin/tests/test_userbar.py
index c43a1bbc0..376c91113 100644
--- a/wagtail/wagtailadmin/tests/test_userbar.py
+++ b/wagtail/wagtailadmin/tests/test_userbar.py
@@ -7,6 +7,7 @@ from django.contrib.auth.models import AnonymousUser
from wagtail.tests.utils import WagtailTestUtils
from wagtail.wagtailcore.models import Page
+from wagtail.tests.testapp.models import BusinessIndex, BusinessChild
class TestUserbarTag(TestCase):
@@ -60,6 +61,37 @@ class TestUserbarFrontend(TestCase, WagtailTestUtils):
self.assertEqual(response.status_code, 403)
+class TestUserbarAddLink(TestCase, WagtailTestUtils):
+ fixtures = ['test.json']
+
+ def setUp(self):
+ self.login()
+ self.homepage = Page.objects.get(url_path='/home/')
+ self.event_index = Page.objects.get(url_path='/home/events/')
+
+ self.business_index = BusinessIndex(title='Business', slug='business', live=True)
+ self.homepage.add_child(instance=self.business_index)
+
+ self.business_child = BusinessChild(title='Business Child', slug='child', live=True)
+ self.business_index.add_child(instance=self.business_child)
+
+ def test_page_allowing_subpages(self):
+ response = self.client.get(reverse('wagtailadmin_userbar_frontend', args=(self.event_index.id, )))
+
+ # page allows subpages, so the 'add page' button should show
+ expected_url = reverse('wagtailadmin_pages_add_subpage', args=(self.event_index.id, ))
+ expected_link = 'Add' % expected_url
+ self.assertContains(response, expected_link)
+
+ def test_page_disallowing_subpages(self):
+ response = self.client.get(reverse('wagtailadmin_userbar_frontend', args=(self.business_child.id, )))
+
+ # page disallows subpages, so the 'add page' button shouldn't show
+ expected_url = reverse('wagtailadmin_pages_add_subpage', args=(self.business_index.id, ))
+ expected_link = 'Add' % expected_url
+ self.assertNotContains(response, expected_link)
+
+
class TestUserbarModeration(TestCase, WagtailTestUtils):
def setUp(self):
self.login()
diff --git a/wagtail/wagtailadmin/tests/tests.py b/wagtail/wagtailadmin/tests/tests.py
index 834c20de5..d4af55f36 100644
--- a/wagtail/wagtailadmin/tests/tests.py
+++ b/wagtail/wagtailadmin/tests/tests.py
@@ -1,10 +1,10 @@
-from django.test import TestCase
+from django.test import TestCase, override_settings
from django.core.urlresolvers import reverse
from django.core import mail
from wagtail.tests.utils import WagtailTestUtils
from wagtail.wagtailcore.models import Page
-from wagtail.wagtailadmin.tasks import send_email_task
+from wagtail.wagtailadmin.utils import send_mail
class TestHome(TestCase, WagtailTestUtils):
@@ -56,15 +56,48 @@ class TestEditorHooks(TestCase, WagtailTestUtils):
self.assertContains(response, '')
-class TestSendEmailTask(TestCase):
+class TestSendMail(TestCase):
def test_send_email(self):
- send_email_task("Test subject", "Test content", ["nobody@email.com"], "test@email.com")
+ send_mail("Test subject", "Test content", ["nobody@email.com"], "test@email.com")
# Check that the email was sent
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].subject, "Test subject")
self.assertEqual(mail.outbox[0].body, "Test content")
self.assertEqual(mail.outbox[0].to, ["nobody@email.com"])
+ self.assertEqual(mail.outbox[0].from_email, "test@email.com")
+
+ @override_settings(WAGTAILADMIN_NOTIFICATION_FROM_EMAIL='anothertest@email.com')
+ def test_send_fallback_to_wagtailadmin_notification_from_email_setting(self):
+ send_mail("Test subject", "Test content", ["nobody@email.com"])
+
+ # Check that the email was sent
+ self.assertEqual(len(mail.outbox), 1)
+ self.assertEqual(mail.outbox[0].subject, "Test subject")
+ self.assertEqual(mail.outbox[0].body, "Test content")
+ self.assertEqual(mail.outbox[0].to, ["nobody@email.com"])
+ self.assertEqual(mail.outbox[0].from_email, "anothertest@email.com")
+
+ @override_settings(DEFAULT_FROM_EMAIL='yetanothertest@email.com')
+ def test_send_fallback_to_default_from_email_setting(self):
+ send_mail("Test subject", "Test content", ["nobody@email.com"])
+
+ # Check that the email was sent
+ self.assertEqual(len(mail.outbox), 1)
+ self.assertEqual(mail.outbox[0].subject, "Test subject")
+ self.assertEqual(mail.outbox[0].body, "Test content")
+ self.assertEqual(mail.outbox[0].to, ["nobody@email.com"])
+ self.assertEqual(mail.outbox[0].from_email, "yetanothertest@email.com")
+
+ def test_send_default_from_email(self):
+ send_mail("Test subject", "Test content", ["nobody@email.com"])
+
+ # Check that the email was sent
+ self.assertEqual(len(mail.outbox), 1)
+ self.assertEqual(mail.outbox[0].subject, "Test subject")
+ self.assertEqual(mail.outbox[0].body, "Test content")
+ self.assertEqual(mail.outbox[0].to, ["nobody@email.com"])
+ self.assertEqual(mail.outbox[0].from_email, "webmaster@localhost")
class TestExplorerNavView(TestCase, WagtailTestUtils):
diff --git a/wagtail/wagtailadmin/userbar.py b/wagtail/wagtailadmin/userbar.py
index 195e936b3..8416255ff 100644
--- a/wagtail/wagtailadmin/userbar.py
+++ b/wagtail/wagtailadmin/userbar.py
@@ -23,8 +23,8 @@ class AddPageItem(BaseItem):
if not request.user.has_perm('wagtailadmin.access_admin'):
return ""
- # Don't render if user doesn't have ability to add siblings
- permission_checker = self.page.get_parent().permissions_for_user(request.user)
+ # Don't render if user doesn't have ability to add children here
+ permission_checker = self.page.permissions_for_user(request.user)
if not permission_checker.can_add_subpage():
return ""
diff --git a/wagtail/wagtailadmin/utils.py b/wagtail/wagtailadmin/utils.py
index 043b8336d..a5cb98a1a 100644
--- a/wagtail/wagtailadmin/utils.py
+++ b/wagtail/wagtailadmin/utils.py
@@ -1,6 +1,13 @@
+from django.template.loader import render_to_string
+from django.core.mail import send_mail as django_send_mail
+from django.conf import settings
+from django.contrib.auth import get_user_model
+from django.db.models import Q
+
from modelcluster.fields import ParentalKey
-from wagtail.wagtailcore.models import Page
+from wagtail.wagtailcore.models import Page, PageRevision, GroupPagePermission
+from wagtail.wagtailusers.models import UserProfile
def get_object_usage(obj):
@@ -34,3 +41,65 @@ def get_object_usage(obj):
)
return pages
+
+
+def users_with_page_permission(page, permission_type, include_superusers=True):
+ # Get user model
+ User = get_user_model()
+
+ # Find GroupPagePermission records of the given type that apply to this page or an ancestor
+ ancestors_and_self = list(page.get_ancestors()) + [page]
+ perm = GroupPagePermission.objects.filter(permission_type=permission_type, page__in=ancestors_and_self)
+ q = Q(groups__page_permissions=perm)
+
+ # Include superusers
+ if include_superusers:
+ q |= Q(is_superuser=True)
+
+ return User.objects.filter(is_active=True).filter(q).distinct()
+
+
+def send_mail(email_subject, email_content, email_addresses, from_email=None):
+ if not from_email:
+ if hasattr(settings, 'WAGTAILADMIN_NOTIFICATION_FROM_EMAIL'):
+ from_email = settings.WAGTAILADMIN_NOTIFICATION_FROM_EMAIL
+ elif hasattr(settings, 'DEFAULT_FROM_EMAIL'):
+ from_email = settings.DEFAULT_FROM_EMAIL
+ else:
+ from_email = 'webmaster@localhost'
+
+ django_send_mail(email_subject, email_content, from_email, email_addresses)
+
+
+def send_notification(page_revision_id, notification, excluded_user_id):
+ # Get revision
+ revision = PageRevision.objects.get(id=page_revision_id)
+
+ # Get list of recipients
+ if notification == 'submitted':
+ # Get list of publishers
+ recipients = users_with_page_permission(revision.page, 'publish')
+ elif notification in ['rejected', 'approved']:
+ # Get submitter
+ recipients = [revision.user]
+ else:
+ return
+
+ # Get list of email addresses
+ email_addresses = [
+ recipient.email for recipient in recipients
+ if recipient.email and recipient.id != excluded_user_id and getattr(UserProfile.get_for_user(recipient), notification + '_notifications')
+ ]
+
+ # Return if there are no email addresses
+ if not email_addresses:
+ return
+
+ # Get email subject and content
+ template = 'wagtailadmin/notifications/' + notification + '.html'
+ rendered_template = render_to_string(template, dict(revision=revision, settings=settings)).split('\n')
+ email_subject = rendered_template[0]
+ email_content = '\n'.join(rendered_template[1:])
+
+ # Send email
+ send_mail(email_subject, email_content, email_addresses)
diff --git a/wagtail/wagtailadmin/views/pages.py b/wagtail/wagtailadmin/views/pages.py
index a707d1df6..e1dd99a58 100644
--- a/wagtail/wagtailadmin/views/pages.py
+++ b/wagtail/wagtailadmin/views/pages.py
@@ -15,7 +15,8 @@ from django.db.models import Count
from wagtail.wagtailadmin.edit_handlers import TabbedInterface, ObjectList
from wagtail.wagtailadmin.forms import SearchForm, CopyForm
-from wagtail.wagtailadmin import tasks, signals
+from wagtail.wagtailadmin.utils import send_notification
+from wagtail.wagtailadmin import signals
from wagtail.wagtailcore import hooks
from wagtail.wagtailcore.models import Page, PageRevision, get_navigation_menu_items
@@ -225,7 +226,7 @@ def create(request, content_type_app_name, content_type_model_name, parent_page_
messages.success(request, _("Page '{0}' published.").format(page.title))
elif is_submitting:
messages.success(request, _("Page '{0}' submitted for moderation.").format(page.title))
- tasks.send_notification.delay(page.get_latest_revision().id, 'submitted', request.user.id)
+ send_notification(page.get_latest_revision().id, 'submitted', request.user.id)
else:
messages.success(request, _("Page '{0}' created.").format(page.title))
@@ -361,7 +362,7 @@ def edit(request, page_id):
messages.button(reverse('wagtailadmin_pages_view_draft', args=(page_id,)), _('View draft')),
messages.button(reverse('wagtailadmin_pages_edit', args=(page_id,)), _('Edit'))
])
- tasks.send_notification.delay(page.get_latest_revision().id, 'submitted', request.user.id)
+ send_notification(page.get_latest_revision().id, 'submitted', request.user.id)
else:
messages.success(request, _("Page '{0}' updated.").format(page.title))
@@ -782,7 +783,7 @@ def approve_moderation(request, revision_id):
if request.method == 'POST':
revision.approve_moderation()
messages.success(request, _("Page '{0}' published.").format(revision.page.title))
- tasks.send_notification.delay(revision.id, 'approved', request.user.id)
+ send_notification(revision.id, 'approved', request.user.id)
return redirect('wagtailadmin_home')
@@ -799,7 +800,7 @@ def reject_moderation(request, revision_id):
if request.method == 'POST':
revision.reject_moderation()
messages.success(request, _("Page '{0}' rejected for publication.").format(revision.page.title))
- tasks.send_notification.delay(revision.id, 'rejected', request.user.id)
+ send_notification(revision.id, 'rejected', request.user.id)
return redirect('wagtailadmin_home')
diff --git a/wagtail/wagtailcore/tests/test_management_commands.py b/wagtail/wagtailcore/tests/test_management_commands.py
index 91fc727dc..01544f3c6 100644
--- a/wagtail/wagtailcore/tests/test_management_commands.py
+++ b/wagtail/wagtailcore/tests/test_management_commands.py
@@ -9,7 +9,7 @@ from django.db import models
from wagtail.wagtailcore.models import Page, PageRevision
from wagtail.wagtailcore.signals import page_published, page_unpublished
-from wagtail.tests.models import SimplePage, EventPage
+from wagtail.tests.testapp.models import SimplePage, EventPage
class TestFixTreeCommand(TestCase):
diff --git a/wagtail/wagtailcore/tests/test_page_model.py b/wagtail/wagtailcore/tests/test_page_model.py
index a5d0a125b..58b8940de 100644
--- a/wagtail/wagtailcore/tests/test_page_model.py
+++ b/wagtail/wagtailcore/tests/test_page_model.py
@@ -11,7 +11,7 @@ from django.contrib.contenttypes.models import ContentType
from django.contrib.auth import get_user_model
from wagtail.wagtailcore.models import Page, Site
-from wagtail.tests.models import EventPage, EventIndex, SimplePage, PageWithOldStyleRouteMethod, BusinessIndex, BusinessSubIndex, BusinessChild, StandardIndex
+from wagtail.tests.testapp.models import EventPage, EventIndex, SimplePage, PageWithOldStyleRouteMethod, BusinessIndex, BusinessSubIndex, BusinessChild, StandardIndex
class TestSiteRouting(TestCase):
diff --git a/wagtail/wagtailcore/tests/test_page_permissions.py b/wagtail/wagtailcore/tests/test_page_permissions.py
index bd2bd3f31..33dfc6e21 100644
--- a/wagtail/wagtailcore/tests/test_page_permissions.py
+++ b/wagtail/wagtailcore/tests/test_page_permissions.py
@@ -2,7 +2,7 @@ from django.test import TestCase
from django.contrib.auth import get_user_model
from wagtail.wagtailcore.models import Page, UserPagePermissionsProxy
-from wagtail.tests.models import EventPage
+from wagtail.tests.testapp.models import EventPage
class TestPagePermission(TestCase):
diff --git a/wagtail/wagtailcore/tests/test_page_queryset.py b/wagtail/wagtailcore/tests/test_page_queryset.py
index c39358d93..3dce6c436 100644
--- a/wagtail/wagtailcore/tests/test_page_queryset.py
+++ b/wagtail/wagtailcore/tests/test_page_queryset.py
@@ -1,7 +1,7 @@
from django.test import TestCase
from wagtail.wagtailcore.models import Page, PageViewRestriction
-from wagtail.tests.models import EventPage
+from wagtail.tests.testapp.models import EventPage
class TestPageQuerySet(TestCase):
diff --git a/wagtail/wagtailcore/tests/test_rich_text.py b/wagtail/wagtailcore/tests/test_rich_text.py
index 8ffb917d8..bc12b4fd7 100644
--- a/wagtail/wagtailcore/tests/test_rich_text.py
+++ b/wagtail/wagtailcore/tests/test_rich_text.py
@@ -12,7 +12,7 @@ from bs4 import BeautifulSoup
class TestPageLinkHandler(TestCase):
- fixtures = ['wagtail/tests/fixtures/test.json']
+ fixtures = ['test.json']
def test_get_db_attributes(self):
soup = BeautifulSoup(
diff --git a/wagtail/wagtailcore/tests/tests.py b/wagtail/wagtailcore/tests/tests.py
index fd2e4de93..c71ab8492 100644
--- a/wagtail/wagtailcore/tests/tests.py
+++ b/wagtail/wagtailcore/tests/tests.py
@@ -7,7 +7,7 @@ from django.utils.safestring import SafeString
from wagtail.wagtailcore.models import Page, Site
from wagtail.wagtailcore.templatetags.wagtailcore_tags import richtext
from wagtail.wagtailcore.utils import resolve_model_string
-from wagtail.tests.models import SimplePage
+from wagtail.tests.testapp.models import SimplePage
class TestPageUrlTags(TestCase):
diff --git a/wagtail/wagtaildocs/tests.py b/wagtail/wagtaildocs/tests.py
index 863ad8e9c..a7943e492 100644
--- a/wagtail/wagtaildocs/tests.py
+++ b/wagtail/wagtaildocs/tests.py
@@ -13,7 +13,7 @@ from django.test.utils import override_settings
from wagtail.tests.utils import WagtailTestUtils
from wagtail.wagtailcore.models import Page
-from wagtail.tests.models import EventPage, EventPageRelatedLink
+from wagtail.tests.testapp.models import EventPage, EventPageRelatedLink
from wagtail.wagtaildocs.models import Document
from wagtail.wagtaildocs import models
@@ -340,7 +340,7 @@ class TestDocumentFilenameProperties(TestCase):
class TestUsageCount(TestCase, WagtailTestUtils):
- fixtures = ['wagtail/tests/fixtures/test.json']
+ fixtures = ['test.json']
def setUp(self):
self.login()
@@ -391,7 +391,7 @@ class TestUsageCount(TestCase, WagtailTestUtils):
class TestGetUsage(TestCase, WagtailTestUtils):
- fixtures = ['wagtail/tests/fixtures/test.json']
+ fixtures = ['test.json']
def setUp(self):
self.login()
@@ -581,7 +581,7 @@ class TestServeView(TestCase):
class TestDocumentRichTextLinkHandler(TestCase):
- fixtures = ['wagtail/tests/fixtures/test.json']
+ fixtures = ['test.json']
def test_get_db_attributes(self):
soup = BeautifulSoup(
diff --git a/wagtail/wagtailembeds/oembed_providers.py b/wagtail/wagtailembeds/oembed_providers.py
index bc944f9bd..30df31b85 100644
--- a/wagtail/wagtailembeds/oembed_providers.py
+++ b/wagtail/wagtailembeds/oembed_providers.py
@@ -76,7 +76,7 @@ OEMBED_ENDPOINTS = {
],
"http://api.instagram.com/oembed": [
"^http://instagr\\.am/p/.+$",
- "^http://instagram\\.com/p/.+$"
+ "^http[s]?://instagram\\.com/p/.+$"
],
"https://www.slideshare.net/api/oembed/2": [
"^http://www\\.slideshare\\.net/.+$"
diff --git a/wagtail/wagtailforms/models.py b/wagtail/wagtailforms/models.py
index 755994dbf..ff3278167 100644
--- a/wagtail/wagtailforms/models.py
+++ b/wagtail/wagtailforms/models.py
@@ -16,7 +16,7 @@ from django.core.serializers.json import DjangoJSONEncoder
from wagtail.wagtailcore.models import Page, Orderable, UserPagePermissionsProxy, get_page_types
from wagtail.wagtailadmin.edit_handlers import FieldPanel
-from wagtail.wagtailadmin import tasks
+from wagtail.wagtailadmin.utils import send_mail
from .forms import FormBuilder
@@ -194,7 +194,7 @@ class AbstractEmailForm(AbstractForm):
if self.to_address:
content = '\n'.join([x[1].label + ': ' + form.data.get(x[0]) for x in form.fields.items()])
- tasks.send_email_task.delay(self.subject, content, [self.to_address], self.from_address,)
+ send_mail(self.subject, content, [self.to_address], self.from_address,)
class Meta:
diff --git a/wagtail/wagtailforms/tests.py b/wagtail/wagtailforms/tests.py
index 25571bcc1..979f2243b 100644
--- a/wagtail/wagtailforms/tests.py
+++ b/wagtail/wagtailforms/tests.py
@@ -8,7 +8,7 @@ from django.core.urlresolvers import reverse
from wagtail.wagtailcore.models import Page
from wagtail.wagtailforms.models import FormSubmission
from wagtail.wagtailforms.forms import FormBuilder
-from wagtail.tests.models import FormPage, FormField
+from wagtail.tests.testapp.models import FormPage, FormField
class TestFormSubmission(TestCase):
diff --git a/wagtail/wagtailimages/models.py b/wagtail/wagtailimages/models.py
index c1844f131..a54c581d4 100644
--- a/wagtail/wagtailimages/models.py
+++ b/wagtail/wagtailimages/models.py
@@ -261,7 +261,7 @@ def image_delete(sender, instance, **kwargs):
def get_image_model():
from django.conf import settings
- from django.db.models import get_model
+ from django.apps import apps
try:
app_label, model_name = settings.WAGTAILIMAGES_IMAGE_MODEL.split('.')
@@ -270,7 +270,7 @@ def get_image_model():
except ValueError:
raise ImproperlyConfigured("WAGTAILIMAGES_IMAGE_MODEL must be of the form 'app_label.model_name'")
- image_model = get_model(app_label, model_name)
+ image_model = apps.get_model(app_label, model_name)
if image_model is None:
raise ImproperlyConfigured("WAGTAILIMAGES_IMAGE_MODEL refers to model '%s' that has not been installed" % settings.WAGTAILIMAGES_IMAGE_MODEL)
return image_model
diff --git a/wagtail/wagtailimages/tests/test_models.py b/wagtail/wagtailimages/tests/test_models.py
index 9abb3b093..5d96a2848 100644
--- a/wagtail/wagtailimages/tests/test_models.py
+++ b/wagtail/wagtailimages/tests/test_models.py
@@ -13,7 +13,7 @@ from django.db import connection
from wagtail.tests.utils import WagtailTestUtils
from wagtail.wagtailcore.models import Page
-from wagtail.tests.models import EventPage, EventPageCarouselItem
+from wagtail.tests.testapp.models import EventPage, EventPageCarouselItem
from wagtail.wagtailimages.models import Rendition, Filter, SourceImageIOError
from wagtail.wagtailimages.rect import Rect
@@ -161,7 +161,7 @@ class TestRenditions(TestCase):
class TestUsageCount(TestCase):
- fixtures = ['wagtail/tests/fixtures/test.json']
+ fixtures = ['test.json']
def setUp(self):
self.image = Image.objects.create(
@@ -184,7 +184,7 @@ class TestUsageCount(TestCase):
class TestGetUsage(TestCase):
- fixtures = ['wagtail/tests/fixtures/test.json']
+ fixtures = ['test.json']
def setUp(self):
self.image = Image.objects.create(
diff --git a/wagtail/wagtailimages/tests/test_rich_text.py b/wagtail/wagtailimages/tests/test_rich_text.py
index a9f91a468..473a6faab 100644
--- a/wagtail/wagtailimages/tests/test_rich_text.py
+++ b/wagtail/wagtailimages/tests/test_rich_text.py
@@ -7,8 +7,6 @@ from wagtail.wagtailimages.rich_text import ImageEmbedHandler
class TestImageEmbedHandler(TestCase):
- fixtures = ['wagtail/tests/fixtures/test.json']
-
def test_get_db_attributes(self):
soup = BeautifulSoup(
'foo'
diff --git a/wagtail/wagtailimages/tests/tests.py b/wagtail/wagtailimages/tests/tests.py
index f1f7bbbd9..3520d01d2 100644
--- a/wagtail/wagtailimages/tests/tests.py
+++ b/wagtail/wagtailimages/tests/tests.py
@@ -13,7 +13,7 @@ from django.db import models
from taggit.forms import TagField, TagWidget
from wagtail.utils.deprecation import RemovedInWagtail12Warning
-from wagtail.tests.models import CustomImageWithAdminFormFields, CustomImageWithoutAdminFormFields
+from wagtail.tests.testapp.models import CustomImageWithAdminFormFields, CustomImageWithoutAdminFormFields
from wagtail.tests.utils import WagtailTestUtils
from wagtail.wagtailimages.utils import generate_signature, verify_signature
from wagtail.wagtailimages.rect import Rect
diff --git a/wagtail/wagtailsearch/index.py b/wagtail/wagtailsearch/index.py
index fa2f317ce..d7326386a 100644
--- a/wagtail/wagtailsearch/index.py
+++ b/wagtail/wagtailsearch/index.py
@@ -3,6 +3,7 @@ import warnings
from six import string_types
from django.db import models
+from django.apps import apps
class Indexed(object):
@@ -74,7 +75,7 @@ class Indexed(object):
def get_indexed_models():
return [
- model for model in models.get_models()
+ model for model in apps.get_models()
if issubclass(model, Indexed) and not model._meta.abstract
]
diff --git a/wagtail/wagtailsearch/tests/test_backends.py b/wagtail/wagtailsearch/tests/test_backends.py
index aad3ee8d8..fc181d6f3 100644
--- a/wagtail/wagtailsearch/tests/test_backends.py
+++ b/wagtail/wagtailsearch/tests/test_backends.py
@@ -8,7 +8,7 @@ from django.conf import settings
from django.core import management
from wagtail.tests.utils import WagtailTestUtils
-from wagtail.tests import models
+from wagtail.tests.search import models
from wagtail.wagtailsearch.backends import get_search_backend, InvalidSearchBackendError
from wagtail.wagtailsearch.backends.db import DBSearch
diff --git a/wagtail/wagtailsearch/tests/test_elasticsearch_backend.py b/wagtail/wagtailsearch/tests/test_elasticsearch_backend.py
index fadae9a36..8e0be1f3a 100644
--- a/wagtail/wagtailsearch/tests/test_elasticsearch_backend.py
+++ b/wagtail/wagtailsearch/tests/test_elasticsearch_backend.py
@@ -8,7 +8,7 @@ import json
from django.test import TestCase
from django.db.models import Q
-from wagtail.tests import models
+from wagtail.tests.search import models
from .test_backends import BackendTests
@@ -186,7 +186,7 @@ class TestElasticSearchQuery(TestCase):
query = self.ElasticSearchQuery(models.SearchTest.objects.all(), "Hello")
# Check it
- expected_result = {'filtered': {'filter': {'prefix': {'content_type': 'tests_searchtest'}}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
+ expected_result = {'filtered': {'filter': {'prefix': {'content_type': 'searchtests_searchtest'}}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
self.assertDictEqual(query.to_es(), expected_result)
def test_none_query_string(self):
@@ -194,7 +194,7 @@ class TestElasticSearchQuery(TestCase):
query = self.ElasticSearchQuery(models.SearchTest.objects.all(), None)
# Check it
- expected_result = {'filtered': {'filter': {'prefix': {'content_type': 'tests_searchtest'}}, 'query': {'match_all': {}}}}
+ expected_result = {'filtered': {'filter': {'prefix': {'content_type': 'searchtests_searchtest'}}, 'query': {'match_all': {}}}}
self.assertDictEqual(query.to_es(), expected_result)
def test_filter(self):
@@ -202,7 +202,7 @@ class TestElasticSearchQuery(TestCase):
query = self.ElasticSearchQuery(models.SearchTest.objects.filter(title="Test"), "Hello")
# Check it
- expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'tests_searchtest'}}, {'term': {'title_filter': 'Test'}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
+ expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'searchtests_searchtest'}}, {'term': {'title_filter': 'Test'}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
self.assertDictEqual(query.to_es(), expected_result)
def test_and_filter(self):
@@ -210,7 +210,7 @@ class TestElasticSearchQuery(TestCase):
query = self.ElasticSearchQuery(models.SearchTest.objects.filter(title="Test", live=True), "Hello")
# Check it
- expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'tests_searchtest'}}, {'and': [{'term': {'live_filter': True}}, {'term': {'title_filter': 'Test'}}]}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
+ expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'searchtests_searchtest'}}, {'and': [{'term': {'live_filter': True}}, {'term': {'title_filter': 'Test'}}]}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
# Make sure field filters are sorted (as they can be in any order which may cause false positives)
query = query.to_es()
@@ -229,7 +229,7 @@ class TestElasticSearchQuery(TestCase):
field_filters[:] = sorted(field_filters, key=lambda f: list(f['term'].keys())[0])
# Check it
- expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'tests_searchtest'}}, {'or': [{'term': {'live_filter': True}}, {'term': {'title_filter': 'Test'}}]}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
+ expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'searchtests_searchtest'}}, {'or': [{'term': {'live_filter': True}}, {'term': {'title_filter': 'Test'}}]}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
self.assertDictEqual(query, expected_result)
def test_negated_filter(self):
@@ -237,7 +237,7 @@ class TestElasticSearchQuery(TestCase):
query = self.ElasticSearchQuery(models.SearchTest.objects.exclude(live=True), "Hello")
# Check it
- expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'tests_searchtest'}}, {'not': {'term': {'live_filter': True}}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
+ expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'searchtests_searchtest'}}, {'not': {'term': {'live_filter': True}}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
self.assertDictEqual(query.to_es(), expected_result)
def test_fields(self):
@@ -245,7 +245,7 @@ class TestElasticSearchQuery(TestCase):
query = self.ElasticSearchQuery(models.SearchTest.objects.all(), "Hello", fields=['title'])
# Check it
- expected_result = {'filtered': {'filter': {'prefix': {'content_type': 'tests_searchtest'}}, 'query': {'match': {'title': 'Hello'}}}}
+ expected_result = {'filtered': {'filter': {'prefix': {'content_type': 'searchtests_searchtest'}}, 'query': {'match': {'title': 'Hello'}}}}
self.assertDictEqual(query.to_es(), expected_result)
def test_exact_lookup(self):
@@ -253,7 +253,7 @@ class TestElasticSearchQuery(TestCase):
query = self.ElasticSearchQuery(models.SearchTest.objects.filter(title__exact="Test"), "Hello")
# Check it
- expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'tests_searchtest'}}, {'term': {'title_filter': 'Test'}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
+ expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'searchtests_searchtest'}}, {'term': {'title_filter': 'Test'}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
self.assertDictEqual(query.to_es(), expected_result)
def test_none_lookup(self):
@@ -261,7 +261,7 @@ class TestElasticSearchQuery(TestCase):
query = self.ElasticSearchQuery(models.SearchTest.objects.filter(title=None), "Hello")
# Check it
- expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'tests_searchtest'}}, {'missing': {'field': 'title_filter'}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
+ expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'searchtests_searchtest'}}, {'missing': {'field': 'title_filter'}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
self.assertDictEqual(query.to_es(), expected_result)
def test_isnull_true_lookup(self):
@@ -269,7 +269,7 @@ class TestElasticSearchQuery(TestCase):
query = self.ElasticSearchQuery(models.SearchTest.objects.filter(title__isnull=True), "Hello")
# Check it
- expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'tests_searchtest'}}, {'missing': {'field': 'title_filter'}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
+ expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'searchtests_searchtest'}}, {'missing': {'field': 'title_filter'}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
self.assertDictEqual(query.to_es(), expected_result)
def test_isnull_false_lookup(self):
@@ -277,7 +277,7 @@ class TestElasticSearchQuery(TestCase):
query = self.ElasticSearchQuery(models.SearchTest.objects.filter(title__isnull=False), "Hello")
# Check it
- expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'tests_searchtest'}}, {'not': {'missing': {'field': 'title_filter'}}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
+ expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'searchtests_searchtest'}}, {'not': {'missing': {'field': 'title_filter'}}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
self.assertDictEqual(query.to_es(), expected_result)
def test_startswith_lookup(self):
@@ -285,7 +285,7 @@ class TestElasticSearchQuery(TestCase):
query = self.ElasticSearchQuery(models.SearchTest.objects.filter(title__startswith="Test"), "Hello")
# Check it
- expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'tests_searchtest'}}, {'prefix': {'title_filter': 'Test'}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
+ expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'searchtests_searchtest'}}, {'prefix': {'title_filter': 'Test'}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
self.assertDictEqual(query.to_es(), expected_result)
def test_gt_lookup(self):
@@ -295,7 +295,7 @@ class TestElasticSearchQuery(TestCase):
query = self.ElasticSearchQuery(models.SearchTest.objects.filter(published_date__gt=datetime.datetime(2014, 4, 29)), "Hello")
# Check it
- expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'tests_searchtest'}}, {'range': {'published_date_filter': {'gt': '2014-04-29'}}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
+ expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'searchtests_searchtest'}}, {'range': {'published_date_filter': {'gt': '2014-04-29'}}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
self.assertDictEqual(query.to_es(), expected_result)
def test_lt_lookup(self):
@@ -303,7 +303,7 @@ class TestElasticSearchQuery(TestCase):
query = self.ElasticSearchQuery(models.SearchTest.objects.filter(published_date__lt=datetime.datetime(2014, 4, 29)), "Hello")
# Check it
- expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'tests_searchtest'}}, {'range': {'published_date_filter': {'lt': '2014-04-29'}}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
+ expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'searchtests_searchtest'}}, {'range': {'published_date_filter': {'lt': '2014-04-29'}}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
self.assertDictEqual(query.to_es(), expected_result)
def test_gte_lookup(self):
@@ -311,7 +311,7 @@ class TestElasticSearchQuery(TestCase):
query = self.ElasticSearchQuery(models.SearchTest.objects.filter(published_date__gte=datetime.datetime(2014, 4, 29)), "Hello")
# Check it
- expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'tests_searchtest'}}, {'range': {'published_date_filter': {'gte': '2014-04-29'}}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
+ expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'searchtests_searchtest'}}, {'range': {'published_date_filter': {'gte': '2014-04-29'}}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
self.assertDictEqual(query.to_es(), expected_result)
def test_lte_lookup(self):
@@ -319,7 +319,7 @@ class TestElasticSearchQuery(TestCase):
query = self.ElasticSearchQuery(models.SearchTest.objects.filter(published_date__lte=datetime.datetime(2014, 4, 29)), "Hello")
# Check it
- expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'tests_searchtest'}}, {'range': {'published_date_filter': {'lte': '2014-04-29'}}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
+ expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'searchtests_searchtest'}}, {'range': {'published_date_filter': {'lte': '2014-04-29'}}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
self.assertDictEqual(query.to_es(), expected_result)
def test_range_lookup(self):
@@ -330,7 +330,7 @@ class TestElasticSearchQuery(TestCase):
query = self.ElasticSearchQuery(models.SearchTest.objects.filter(published_date__range=(start_date, end_date)), "Hello")
# Check it
- expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'tests_searchtest'}}, {'range': {'published_date_filter': {'gte': '2014-04-29', 'lte': '2014-08-19'}}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
+ expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'searchtests_searchtest'}}, {'range': {'published_date_filter': {'gte': '2014-04-29', 'lte': '2014-08-19'}}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
self.assertDictEqual(query.to_es(), expected_result)
@@ -358,7 +358,7 @@ class TestElasticSearchMapping(TestCase):
self.obj.save()
def test_get_document_type(self):
- self.assertEqual(self.es_mapping.get_document_type(), 'tests_searchtest')
+ self.assertEqual(self.es_mapping.get_document_type(), 'searchtests_searchtest')
def test_get_mapping(self):
# Build mapping
@@ -366,7 +366,7 @@ class TestElasticSearchMapping(TestCase):
# Check
expected_result = {
- 'tests_searchtest': {
+ 'searchtests_searchtest': {
'properties': {
'pk': {'index': 'not_analyzed', 'type': 'string', 'store': 'yes', 'include_in_all': False},
'content_type': {'index': 'not_analyzed', 'type': 'string', 'include_in_all': False},
@@ -384,7 +384,7 @@ class TestElasticSearchMapping(TestCase):
self.assertDictEqual(mapping, expected_result)
def test_get_document_id(self):
- self.assertEqual(self.es_mapping.get_document_id(self.obj), 'tests_searchtest:' + str(self.obj.pk))
+ self.assertEqual(self.es_mapping.get_document_id(self.obj), 'searchtests_searchtest:' + str(self.obj.pk))
def test_get_document(self):
# Get document
@@ -393,7 +393,7 @@ class TestElasticSearchMapping(TestCase):
# Check
expected_result = {
'pk': str(self.obj.pk),
- 'content_type': 'tests_searchtest',
+ 'content_type': 'searchtests_searchtest',
'_partials': ['Hello'],
'live_filter': False,
'published_date_filter': None,
@@ -430,7 +430,7 @@ class TestElasticSearchMappingInheritance(TestCase):
self.obj.save()
def test_get_document_type(self):
- self.assertEqual(self.es_mapping.get_document_type(), 'tests_searchtest_tests_searchtestchild')
+ self.assertEqual(self.es_mapping.get_document_type(), 'searchtests_searchtest_searchtests_searchtestchild')
def test_get_mapping(self):
# Build mapping
@@ -438,7 +438,7 @@ class TestElasticSearchMappingInheritance(TestCase):
# Check
expected_result = {
- 'tests_searchtest_tests_searchtestchild': {
+ 'searchtests_searchtest_searchtests_searchtestchild': {
'properties': {
# New
'extra_content': {'type': 'string', 'include_in_all': True},
@@ -464,7 +464,7 @@ class TestElasticSearchMappingInheritance(TestCase):
# This must be tests_searchtest instead of 'tests_searchtest_tests_searchtestchild'
# as it uses the contents base content type name.
# This prevents the same object being accidentally indexed twice.
- self.assertEqual(self.es_mapping.get_document_id(self.obj), 'tests_searchtest:' + str(self.obj.pk))
+ self.assertEqual(self.es_mapping.get_document_id(self.obj), 'searchtests_searchtest:' + str(self.obj.pk))
def test_get_document(self):
# Build document
@@ -481,7 +481,7 @@ class TestElasticSearchMappingInheritance(TestCase):
'subtitle': 'World',
# Changed
- 'content_type': 'tests_searchtest_tests_searchtestchild',
+ 'content_type': 'searchtests_searchtest_searchtests_searchtestchild',
# Inherited
'pk': str(self.obj.pk),
diff --git a/wagtail/wagtailsearch/tests/test_frontend.py b/wagtail/wagtailsearch/tests/test_frontend.py
index ba19b4396..e5c754d9b 100644
--- a/wagtail/wagtailsearch/tests/test_frontend.py
+++ b/wagtail/wagtailsearch/tests/test_frontend.py
@@ -5,7 +5,7 @@ from django.core import paginator
from wagtail.wagtailcore.models import Page
from wagtail.wagtailsearch.models import Query
-from wagtail.tests.models import EventPage
+from wagtail.tests.testapp.models import EventPage
class TestSearchView(TestCase):
diff --git a/wagtail/wagtailsearch/tests/test_indexed_class.py b/wagtail/wagtailsearch/tests/test_indexed_class.py
index d4ed79b66..91cc2b51a 100644
--- a/wagtail/wagtailsearch/tests/test_indexed_class.py
+++ b/wagtail/wagtailsearch/tests/test_indexed_class.py
@@ -3,18 +3,18 @@ import warnings
from django.test import TestCase
from wagtail.wagtailsearch import index
-from wagtail.tests import models
+from wagtail.tests.search import models
from wagtail.tests.utils import WagtailTestUtils
class TestContentTypeNames(TestCase):
def test_base_content_type_name(self):
name = models.SearchTestChild.indexed_get_toplevel_content_type()
- self.assertEqual(name, 'tests_searchtest')
+ self.assertEqual(name, 'searchtests_searchtest')
def test_qualified_content_type_name(self):
name = models.SearchTestChild.indexed_get_content_type()
- self.assertEqual(name, 'tests_searchtest_tests_searchtestchild')
+ self.assertEqual(name, 'searchtests_searchtest_searchtests_searchtestchild')
class TestSearchFields(TestCase):
diff --git a/wagtail/wagtailsearch/tests/test_signal_handlers.py b/wagtail/wagtailsearch/tests/test_signal_handlers.py
index ffdd143cf..001b798f9 100644
--- a/wagtail/wagtailsearch/tests/test_signal_handlers.py
+++ b/wagtail/wagtailsearch/tests/test_signal_handlers.py
@@ -1,7 +1,7 @@
from django.test import TestCase
from wagtail.wagtailsearch import signal_handlers
-from wagtail.tests import models
+from wagtail.tests.search import models
class TestGetIndexedInstance(TestCase):
diff --git a/wagtail/wagtailsnippets/tests.py b/wagtail/wagtailsnippets/tests.py
index 3f41b7e99..996853dad 100644
--- a/wagtail/wagtailsnippets/tests.py
+++ b/wagtail/wagtailsnippets/tests.py
@@ -2,10 +2,11 @@ from django.http import Http404
from django.test import TestCase
from django.core.urlresolvers import reverse
from django.db import models
+from django.test.utils import override_settings
from wagtail.tests.utils import WagtailTestUtils
-from django.test.utils import override_settings
-from wagtail.tests.models import Advert, AlphaSnippet, ZuluSnippet, SnippetChooserModel, RegisterDecorator, RegisterFunction
+from wagtail.tests.testapp.models import Advert, SnippetChooserModel
+from wagtail.tests.snippets.models import AlphaSnippet, ZuluSnippet, RegisterDecorator, RegisterFunction
from wagtail.wagtailsnippets.models import register_snippet, SNIPPET_MODELS
from wagtail.wagtailsnippets.views.snippets import (
@@ -91,7 +92,7 @@ class TestSnippetCreateView(TestCase, WagtailTestUtils):
class TestSnippetEditView(TestCase, WagtailTestUtils):
- fixtures = ['wagtail/tests/fixtures/test.json']
+ fixtures = ['test.json']
def setUp(self):
self.test_snippet = Advert.objects.get(id=1)
@@ -138,7 +139,7 @@ class TestSnippetEditView(TestCase, WagtailTestUtils):
class TestSnippetDelete(TestCase, WagtailTestUtils):
- fixtures = ['wagtail/tests/fixtures/test.json']
+ fixtures = ['test.json']
def setUp(self):
self.test_snippet = Advert.objects.get(id=1)
@@ -160,7 +161,7 @@ class TestSnippetDelete(TestCase, WagtailTestUtils):
class TestSnippetChooserPanel(TestCase):
- fixtures = ['wagtail/tests/fixtures/test.json']
+ fixtures = ['test.json']
def setUp(self):
model = SnippetChooserModel
@@ -213,7 +214,7 @@ class TestSnippetOrdering(TestCase):
class TestUsageCount(TestCase):
- fixtures = ['wagtail/tests/fixtures/test.json']
+ fixtures = ['test.json']
@override_settings(WAGTAIL_USAGE_COUNT_ENABLED=True)
def test_snippet_usage_count(self):
@@ -222,7 +223,7 @@ class TestUsageCount(TestCase):
class TestUsedBy(TestCase):
- fixtures = ['wagtail/tests/fixtures/test.json']
+ fixtures = ['test.json']
@override_settings(WAGTAIL_USAGE_COUNT_ENABLED=True)
def test_snippet_used_by(self):
@@ -231,7 +232,7 @@ class TestUsedBy(TestCase):
class TestSnippetChoose(TestCase, WagtailTestUtils):
- fixtures = ['wagtail/tests/fixtures/test.json']
+ fixtures = ['test.json']
def setUp(self):
self.login()
@@ -255,7 +256,7 @@ class TestSnippetChoose(TestCase, WagtailTestUtils):
class TestSnippetChosen(TestCase, WagtailTestUtils):
- fixtures = ['wagtail/tests/fixtures/test.json']
+ fixtures = ['test.json']
def setUp(self):
self.login()