mirror of
https://github.com/Hopiu/wagtail.git
synced 2026-04-30 11:34:49 +00:00
Merge branch 'master' into kaedroho-project-template
This commit is contained in:
commit
27bc0e5c9f
161 changed files with 5281 additions and 940 deletions
|
|
@ -5,6 +5,7 @@ branch = True
|
|||
source = wagtail
|
||||
|
||||
omit =
|
||||
*/south_migrations/*
|
||||
*/migrations/*
|
||||
wagtail/vendor/*
|
||||
|
||||
|
|
@ -31,4 +32,4 @@ exclude_lines =
|
|||
ignore_errors = True
|
||||
|
||||
[html]
|
||||
directory = coverage_html_report
|
||||
directory = coverage_html_report
|
||||
|
|
|
|||
31
.travis.yml
31
.travis.yml
|
|
@ -1,29 +1,38 @@
|
|||
language: python
|
||||
# Test matrix
|
||||
python:
|
||||
- 2.7
|
||||
- 3.2
|
||||
- 3.4
|
||||
env:
|
||||
- DJANGO_VERSION=Django==1.6.5
|
||||
#- DJANGO_VERSION=Django==1.7.0
|
||||
# - TOXENV=py26-dj16-postgres
|
||||
- TOXENV=py26-dj16-sqlite
|
||||
- TOXENV=py27-dj16-postgres
|
||||
# - TOXENV=py27-dj16-sqlite
|
||||
- TOXENV=py32-dj16-postgres
|
||||
# - TOXENV=py33-dj16-postgres
|
||||
- TOXENV=py34-dj16-postgres
|
||||
- TOXENV=py27-dj17-postgres
|
||||
# - TOXENV=py27-dj17-sqlite
|
||||
# - TOXENV=py32-dj17-postgres
|
||||
# - TOXENV=py33-dj17-postgres
|
||||
- TOXENV=py34-dj17-postgres
|
||||
|
||||
# Services
|
||||
services:
|
||||
- redis-server
|
||||
- elasticsearch
|
||||
|
||||
# Package installation
|
||||
install:
|
||||
- python setup.py install
|
||||
- pip install psycopg2 elasticsearch wand embedly mock python-dateutil
|
||||
- pip install coveralls
|
||||
- pip install tox coveralls
|
||||
|
||||
# Pre-test configuration
|
||||
before_script:
|
||||
- psql -c 'create database wagtaildemo;' -U postgres
|
||||
|
||||
# Run the tests
|
||||
script:
|
||||
coverage run runtests.py
|
||||
tox
|
||||
|
||||
after_success:
|
||||
coveralls
|
||||
|
||||
# Who to notify about build results
|
||||
notifications:
|
||||
email:
|
||||
|
|
|
|||
|
|
@ -3,7 +3,16 @@ Changelog
|
|||
|
||||
0.6 (xx.xx.20xx)
|
||||
~~~~~~~~~~~~~~~~
|
||||
* Added Django 1.7 support
|
||||
* Added {% routablepageurl %} template tag (@timheap)
|
||||
* Added RoutablePageMixin (@timheap)
|
||||
* MenuItems can now have bundled JavaScript
|
||||
* Added a new hook for registering admin menu items
|
||||
* Renamed wagtailsearch.indexed to wagtailsearch.index
|
||||
* Fix: Page URL generation now returns correct URLs for sites that have the main 'serve' view rooted somewhere other than '/'
|
||||
* Fix: Search results in the page chooser now respect the page_type parameter on PageChooserPanel
|
||||
* Fix: Rendition filenames are now prevented from going over 60 chars, even with a large focal_point_key
|
||||
* Fix: Child relations that are defined on a model's superclass (such as the base Page model) are now picked up correctly by the page editing form, page copy operations and the replace_text management command
|
||||
|
||||
0.5 (01.08.2014)
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
|
|
|||
12
README.rst
12
README.rst
|
|
@ -24,8 +24,8 @@ Wagtail is a Django content management system built originally for the `Royal Co
|
|||
* Support for tree-based content organisation
|
||||
* Optional preview->submit->approve workflow
|
||||
* Fast out of the box. `Varnish <https://www.varnish-cache.org/>`_-friendly if you need it
|
||||
* A simple `form builder <http://docs.wagtail.io/en/latest/form_builder.html>`_
|
||||
* Optional `static site generation <http://docs.wagtail.io/en/latest/static_site_generation.html>`_
|
||||
* A simple `form builder <http://docs.wagtail.io/en/latest/core_components/form_builder.html>`_
|
||||
* Optional `static site generation <http://docs.wagtail.io/en/latest/contrib_components/static_site_generation.html>`_
|
||||
* Excellent `test coverage <https://coveralls.io/r/torchbox/wagtail?branch=master>`_
|
||||
|
||||
Find out more at `wagtail.io <http://wagtail.io/>`_.
|
||||
|
|
@ -45,9 +45,7 @@ Available at `wagtail.readthedocs.org <http://wagtail.readthedocs.org/>`_ and al
|
|||
|
||||
Compatibility
|
||||
~~~~~~~~~~~~~
|
||||
Wagtail supports Django 1.6.2+ on Python 2.6, 2.7, 3.2, 3.3 and 3.4.
|
||||
|
||||
Django 1.7 support is in progress pending further release candidate testing.
|
||||
Wagtail supports Django 1.6.2+ and 1.7rc3+ on Python 2.6, 2.7, 3.2, 3.3 and 3.4.
|
||||
|
||||
Wagtail's dependencies are summarised at `requirements.io <https://requires.io/github/torchbox/wagtail/requirements>`_.
|
||||
|
||||
|
|
@ -55,8 +53,8 @@ Contributing
|
|||
~~~~~~~~~~~~
|
||||
If you're a Python or Django developer, fork the repo and get stuck in!
|
||||
|
||||
We suggest you start by checking the `Help develop me! <https://github.com/torchbox/wagtail/issues?labels=Help+develop+me%21>`_ label and the `coding guidelines <http://wagtail.readthedocs.org/en/latest/contributing.html#coding-guidelines>`_.
|
||||
We suggest you start by checking the `Help develop me! <https://github.com/torchbox/wagtail/issues?labels=Help+develop+me%21>`_ label and the `coding guidelines <http://wagtail.readthedocs.org/en/latest/howto/contributing.html#coding-guidelines>`_.
|
||||
|
||||
Send us a useful pull request and we'll post you a `t-shirt <https://twitter.com/WagtailCMS/status/432166799464210432/photo/1>`_.
|
||||
|
||||
We also welcome `translations <http://wagtail.readthedocs.org/en/latest/contributing.html#translations>`_ for Wagtail's interface.
|
||||
We also welcome `translations <http://wagtail.readthedocs.org/en/latest/howto/contributing.html#translations>`_ for Wagtail's interface.
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ Using the URLs on your website or blog
|
|||
|
||||
Once you have generated a URL, you can put it straight into the ``src`` attribute of an ``<img>`` tag:
|
||||
|
||||
..code-block:: html
|
||||
.. code-block:: html
|
||||
|
||||
<img src="(image url here)">
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ Core components
|
|||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
sites
|
||||
pages/index
|
||||
images/index
|
||||
snippets
|
||||
|
|
|
|||
|
|
@ -1,88 +0,0 @@
|
|||
.. _routable_page:
|
||||
|
||||
====================================
|
||||
Embedding URL configuration in Pages
|
||||
====================================
|
||||
|
||||
.. versionadded:: 0.5
|
||||
|
||||
The ``RoutablePage`` class provides a convenient way for a page to respond on multiple sub-URLs with different views. For example, a blog section on a site might provide several different types of index page at URLs like ``/blog/2013/06/``, ``/blog/authors/bob/``, ``/blog/tagged/python/``, all served by the same ``BlogIndex`` page.
|
||||
|
||||
A ``RoutablePage`` exists within the page tree like any other page, but URL paths underneath it are checked against a list of patterns, using Django's urlconf scheme. If none of the patterns match, control is passed to subpages as usual (or failing that, a 404 error is thrown).
|
||||
|
||||
|
||||
The basics
|
||||
==========
|
||||
|
||||
To use ``RoutablePage``, you need to make your class inherit from :class:`wagtail.contrib.wagtailroutablepage.models.RoutablePage` and configure the ``subpage_urls`` attribute with your URL configuration.
|
||||
|
||||
Here's an example of an ``EventPage`` with three views:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django.conf.urls import url
|
||||
|
||||
from wagtail.contrib.wagtailroutablepage.models import RoutablePage
|
||||
|
||||
|
||||
class EventPage(RoutablePage):
|
||||
subpage_urls = (
|
||||
url(r'^$', 'current_events', name='current_events'),
|
||||
url(r'^past/$', 'past_events', name='past_events'),
|
||||
url(r'^year/(\d+)/$', 'events_for_year', name='events_for_year'),
|
||||
)
|
||||
|
||||
def current_events(self, request):
|
||||
"""
|
||||
View function for the current events page
|
||||
"""
|
||||
...
|
||||
|
||||
def past_events(self, request):
|
||||
"""
|
||||
View function for the current events page
|
||||
"""
|
||||
...
|
||||
|
||||
def events_for_year(self, request):
|
||||
"""
|
||||
View function for the events for year page
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
The ``RoutablePage`` class
|
||||
==========================
|
||||
|
||||
.. automodule:: wagtail.contrib.wagtailroutablepage.models
|
||||
.. autoclass:: RoutablePage
|
||||
|
||||
.. autoattribute:: subpage_urls
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django.conf.urls import url
|
||||
|
||||
subpage_urls = (
|
||||
url(r'^$', 'serve', name='main'),
|
||||
url(r'^archive/$', 'archive', name='archive'),
|
||||
)
|
||||
|
||||
.. automethod:: resolve_subpage
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
view, args, kwargs = page.resolve_subpage('/past/')
|
||||
response = view(request, *args, **kwargs)
|
||||
|
||||
.. automethod:: reverse_subpage
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
url = page.url + page.reverse_subpage('events_for_year', args=('2014', ))
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
.. _routable_page_mixin:
|
||||
|
||||
====================================
|
||||
Embedding URL configuration in Pages
|
||||
====================================
|
||||
|
||||
.. versionadded:: 0.6
|
||||
|
||||
The ``RoutablePageMixin`` mixin provides a convenient way for a page to respond on multiple sub-URLs with different views. For example, a blog section on a site might provide several different types of index page at URLs like ``/blog/2013/06/``, ``/blog/authors/bob/``, ``/blog/tagged/python/``, all served by the same ``BlogIndex`` page.
|
||||
|
||||
A ``Page`` using ``RoutablePageMixin`` exists within the page tree like any other page, but URL paths underneath it are checked against a list of patterns, using Django's urlconf scheme. If none of the patterns match, control is passed to subpages as usual (or failing that, a 404 error is thrown).
|
||||
|
||||
|
||||
The basics
|
||||
==========
|
||||
|
||||
To use ``RoutablePageMixin``, you need to make your class inherit from both :class:`wagtail.contrib.wagtailroutablepage.models.RoutablePageMixin` and :class:`wagtail.wagtailcore.models.Page`, and configure the ``subpage_urls`` attribute with your URL configuration.
|
||||
|
||||
Here's an example of an ``EventPage`` with three views:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django.conf.urls import url
|
||||
|
||||
from wagtail.contrib.wagtailroutablepage.models import RoutablePageMixin
|
||||
from wagtail.wagtailcore.models import Page
|
||||
|
||||
|
||||
class EventPage(RoutablePageMixin, Page):
|
||||
subpage_urls = (
|
||||
url(r'^$', 'current_events', name='current_events'),
|
||||
url(r'^past/$', 'past_events', name='past_events'),
|
||||
url(r'^year/(\d+)/$', 'events_for_year', name='events_for_year'),
|
||||
)
|
||||
|
||||
def current_events(self, request):
|
||||
"""
|
||||
View function for the current events page
|
||||
"""
|
||||
...
|
||||
|
||||
def past_events(self, request):
|
||||
"""
|
||||
View function for the past events page
|
||||
"""
|
||||
...
|
||||
|
||||
def events_for_year(self, request):
|
||||
"""
|
||||
View function for the events for year page
|
||||
"""
|
||||
...
|
||||
|
||||
|
||||
The ``RoutablePageMixin`` class
|
||||
===============================
|
||||
|
||||
.. automodule:: wagtail.contrib.wagtailroutablepage.models
|
||||
.. autoclass:: RoutablePageMixin
|
||||
|
||||
.. autoattribute:: subpage_urls
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django.conf.urls import url
|
||||
|
||||
from wagtail.wagtailcore.models import Page
|
||||
|
||||
|
||||
class MyPage(RoutablePageMixin, Page):
|
||||
subpage_urls = (
|
||||
url(r'^$', 'main', name='main'),
|
||||
url(r'^archive/$', 'archive', name='archive'),
|
||||
url(r'^archive/(?P<year>[0-9]{4})/$', 'archive', name='archive'),
|
||||
)
|
||||
|
||||
def main(self, request):
|
||||
...
|
||||
|
||||
def archive(self, request, year=None):
|
||||
...
|
||||
|
||||
.. automethod:: resolve_subpage
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
view, args, kwargs = page.resolve_subpage('/archive/')
|
||||
response = view(request, *args, **kwargs)
|
||||
|
||||
.. automethod:: reverse_subpage
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
url = page.url + page.reverse_subpage('archive', kwargs={'year': '2014'})
|
||||
|
||||
|
||||
.. _routablepageurl_template_tag:
|
||||
|
||||
The ``routablepageurl`` template tag
|
||||
====================================
|
||||
|
||||
.. currentmodule:: wagtail.contrib.wagtailroutablepage.templatetags.wagtailroutablepage_tags
|
||||
.. autofunction:: routablepageurl
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
{% load wagtailroutablepage_tags %}
|
||||
|
||||
{% routablepageurl self "feed" %}
|
||||
{% routablepageurl self "archive" 2014 08 14 %}
|
||||
{% routablepageurl self "food" foo="bar" baz="quux" %}
|
||||
|
|
@ -2,40 +2,15 @@
|
|||
Creating page models
|
||||
====================
|
||||
|
||||
Wagtail provides a ``Page`` class to represent types of page (a.k.a Content types). Developers should subclass ``Page`` for their own page models.
|
||||
|
||||
The Page Class
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
``Page`` uses Django's model interface, so you can include any field type and field options that Django allows. Wagtail provides some fields and editing handlers that simplify data entry in the Wagtail admin interface, so you may want to keep those in mind when deciding what properties to add to your models in addition to those already provided by ``Page``.
|
||||
``Page`` uses Django's model interface, so you can include any field type and field options that Django allows. Wagtail provides some field types of its own which simplify data entry in the Wagtail admin interface. Wagtail also wraps Django's field types and widgets with its own concept of "Edit Handlers" and "Panels". These further improve the data entry experience.
|
||||
|
||||
|
||||
Built-in Properties of the Page Class
|
||||
-------------------------------------
|
||||
An example Wagtail Page Model
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Wagtail provides some properties in the ``Page`` class which are common to most webpages. Since you'll be subclassing ``Page``, you don't have to worry about implementing them.
|
||||
|
||||
Public Properties
|
||||
`````````````````
|
||||
|
||||
``title`` (string, required)
|
||||
Human-readable title for the content
|
||||
|
||||
``slug`` (string, required)
|
||||
Machine-readable URL component for this piece of content. The name of the page as it will appear in URLs e.g ``http://domain.com/blog/[my-slug]/``
|
||||
|
||||
``seo_title`` (string)
|
||||
Alternate SEO-crafted title which overrides the normal title for use in the ``<head>`` of a page
|
||||
|
||||
``search_description`` (string)
|
||||
A SEO-crafted description of the content, used in both internal search indexing and for the meta description read by search engines
|
||||
|
||||
The ``Page`` class actually has alot more to it, but these are probably the only built-in properties you'll need to worry about when creating templates for your models.
|
||||
|
||||
|
||||
Anatomy of a Wagtail Model
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
So what does a Wagtail model definition look like? Here's a model representing a typical blog post:
|
||||
This example represents a typical blog post:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
|
@ -58,6 +33,8 @@ So what does a Wagtail model definition look like? Here's a model representing a
|
|||
related_name='+'
|
||||
)
|
||||
|
||||
|
||||
|
||||
BlogPage.content_panels = [
|
||||
FieldPanel('title', classname="full title"),
|
||||
FieldPanel('date'),
|
||||
|
|
@ -72,17 +49,48 @@ So what does a Wagtail model definition look like? Here's a model representing a
|
|||
ImageChooserPanel('feed_image'),
|
||||
]
|
||||
|
||||
To keep track of your ``Page``-derived models, it might be helpful to include "Page" as the last part of your class name. ``BlogPage`` defines three properties: ``body``, ``date``, and ``feed_image``. These are a mix of basic Django models (``DateField``), Wagtail fields (``RichTextField``), and a pointer to a Wagtail model (``Image``).
|
||||
.. tip::
|
||||
To keep track of ``Page`` models and avoid class name clashes, it can be helpful to suffix model class names with "Page" e.g BlogPage, ListingIndexPage.
|
||||
|
||||
Next, the ``content_panels`` and ``promote_panels`` lists define the capabilities and layout of the Wagtail admin page edit interface. The lists are filled with "panels" and "choosers", which will provide a fine-grain interface for inputting the model's content. The ``ImageChooserPanel``, for instance, lets one browse the image library, upload new images, and input image metadata. The ``RichTextField`` is the basic field for creating web-ready website rich text, including text formatting and embedded media like images and video. The Wagtail admin offers other choices for fields, Panels, and Choosers, with the option of creating your own to precisely fit your content without workarounds or other compromises.
|
||||
In the example above the ``BlogPage`` class defines three properties: ``body``, ``date``, and ``feed_image``. These are a mix of basic Django models (``DateField``), Wagtail fields (``RichTextField``), and a pointer to a Wagtail model (``Image``).
|
||||
|
||||
Below that the ``content_panels`` and ``promote_panels`` lists define the capabilities and layout of the page editing interface in the Wagtail admin. The lists are filled with "panels" and "choosers", which will provide a fine-grain interface for inputting the model's content. The ``ImageChooserPanel``, for instance, lets one browse the image library, upload new images and input image metadata. The ``RichTextField`` is the basic field for creating web-ready website rich text, including text formatting and embedded media like images and video. The Wagtail admin offers other choices for fields, Panels, and Choosers, with the option of creating your own to precisely fit your content without workarounds or other compromises.
|
||||
|
||||
Your models may be even more complex, with methods overriding the built-in functionality of the ``Page`` to achieve webdev magic. Or, you can keep your models simple and let Wagtail's built-in functionality do the work.
|
||||
|
||||
Now that we have a basic idea of how our content is defined, lets look at relationships between pieces of content.
|
||||
|
||||
``Page`` Class Reference
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Default fields
|
||||
--------------
|
||||
|
||||
Wagtail provides some fields for the ``Page`` class by default, which will be common to all your pages. You don't need to add these fields to your own page models however you do need to allocate them to ``content_panels``, ``promote_panels`` or ``settings_panels``. See above example and for further information on the panels see :ref:`editing-api`.
|
||||
|
||||
``title`` (string, required)
|
||||
Human-readable title of the page - what you'd probably use as your ``<h1>`` tag.
|
||||
|
||||
``slug`` (string, required)
|
||||
Machine-readable URL component for this page. The name of the page as it will appear in URLs e.g ``http://domain.com/blog/[my-slug]/``
|
||||
|
||||
``seo_title`` (string)
|
||||
Alternate SEO-crafted title, mainly for use in the page ``<title>`` tag.
|
||||
|
||||
``search_description`` (string)
|
||||
SEO-crafted description of the content, used for internal search indexing, suitable for your page's ``<meta name="description">`` tag.
|
||||
|
||||
``show_in_menus`` (boolean)
|
||||
Toggles whether the page should be considered for inclusion in any site-wide menus you create.
|
||||
|
||||
``go_live_at`` (datetime)
|
||||
A datetime on which the page should be automatically made published (made publicly accessible)
|
||||
|
||||
``expire_at`` (datetime)
|
||||
A datetime on which the page should be unpublished, rendering it inaccessible to the public.
|
||||
|
||||
|
||||
Page Properties and Methods Reference
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Page Attributes, Properties and Methods Reference
|
||||
-------------------------------------------------
|
||||
|
||||
In addition to the model fields provided, ``Page`` has many properties and methods that you may wish to reference, use, or override in creating your own models. Those listed here are relatively straightforward to use, but consult the Wagtail source code for a full view of what's possible.
|
||||
|
||||
|
|
@ -121,14 +129,68 @@ In addition to the model fields provided, ``Page`` has many properties and metho
|
|||
|
||||
.. automethod:: search
|
||||
|
||||
.. attribute:: search_fields
|
||||
|
||||
A list of fields to be indexed by the search engine. See Search docs :ref:`wagtailsearch_for_python_developers`
|
||||
|
||||
.. _wagtail_site_admin:
|
||||
.. attribute:: subpage_types
|
||||
|
||||
Site
|
||||
A whitelist of page models which can be created as children of this page type e.g a ``BlogIndex`` page might allow ``BlogPage``, but not ``JobPage`` e.g
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class BlogIndex(Page):
|
||||
subpage_types = ['mysite.BlogPage', 'mysite.BlogArchivePage']
|
||||
|
||||
.. attribute:: password_required_template
|
||||
|
||||
Defines which template file should be used to render the login form for Protected pages using this model. This overrides the default, defined using ``PASSWORD_REQUIRED_TEMPLATE`` in your settings. See :ref:`private_pages`
|
||||
|
||||
|
||||
Tips
|
||||
~~~~
|
||||
|
||||
Django's built-in admin interface provides the way to map a "site" (hostname or domain) to any node in the wagtail tree, using that node as the site's root.
|
||||
Friendly model names
|
||||
--------------------
|
||||
|
||||
Access this by going to ``/django-admin/`` and then "Home › Wagtailcore › Sites." To try out a development site, add a single site with the hostname ``localhost`` at port ``8000`` and map it to one of the pieces of content you have created.
|
||||
Make your model names more friendly to users of Wagtail using Django's internal ``Meta`` class with a ``verbose_name`` e.g
|
||||
|
||||
Wagtail's developers plan to move the site settings into the Wagtail admin interface.
|
||||
.. code-block:: python
|
||||
|
||||
class HomePage(Page):
|
||||
...
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Homepage"
|
||||
|
||||
When users are given a choice of pages to create, the list of page types is generated by splitting your model names on each of their capital letters. Thus a ``HomePage`` model would be named "Home Page" which is a little clumsy. ``verbose_name`` as in the example above, would change this to read "Homepage" which is slightly more conventional.
|
||||
|
||||
The above example also ensures the name of the
|
||||
|
||||
Helpful model descriptions
|
||||
--------------------------
|
||||
|
||||
As your site becomes more complex users may require some prompting in deciding which content type to use when creating a new page. Developers can add a description to their Models by extending Django's internal model ``Meta`` class.
|
||||
|
||||
Insert the following once at the top of your ``models.py``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import django.db.models.options as options
|
||||
options.DEFAULT_NAMES = options.DEFAULT_NAMES + ('description',)
|
||||
|
||||
|
||||
Then for each model as necessary, add a description option to the model ``Meta`` class
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class HomePage(Page):
|
||||
...
|
||||
|
||||
class Meta:
|
||||
description = "The top level homepage for your site"
|
||||
verbose_name = "Homepage"
|
||||
|
||||
|
||||
(This method can be used to extend the Model Meta class in various ways however Wagtail only supports the addition of a ``description`` option).
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
.. _editing-api:
|
||||
|
||||
Defining models with the Editing API
|
||||
Displaying fields with the Editing API
|
||||
====================================
|
||||
|
||||
.. note::
|
||||
|
|
@ -528,10 +529,19 @@ The available hooks are:
|
|||
url(r'^how_did_you_almost_know_my_name/$', admin_view, name='frank' ),
|
||||
]
|
||||
|
||||
.. _construct_main_menu:
|
||||
.. _register_admin_menu_item:
|
||||
|
||||
``construct_main_menu``
|
||||
Add, remove, or alter ``MenuItem`` objects from the Wagtail admin menu. The callable passed to this hook must take a ``request`` object and a list of ``menu_items``; it must return a list of menu items. New items can be constructed from the ``MenuItem`` class by passing in: a ``label`` which will be the text in the menu item, the URL of the admin page you want the menu item to link to (usually by calling ``reverse()`` on the admin view you've set up), CSS class ``name`` applied to the wrapping ``<li>`` of the menu item as ``"menu-{name}"``, CSS ``classnames`` which are used to give the link an icon, and an ``order`` integer which determine's the item's place in the menu.
|
||||
``register_admin_menu_item``
|
||||
.. versionadded:: 0.6
|
||||
|
||||
Add an item to the Wagtail admin menu. The callable passed to this hook must return an instance of ``wagtail.wagtailadmin.menu.MenuItem``. New items can be constructed from the ``MenuItem`` class by passing in a ``label`` which will be the text in the menu item, and the URL of the admin page you want the menu item to link to (usually by calling ``reverse()`` on the admin view you've set up). Additionally, the following keyword arguments are accepted:
|
||||
|
||||
:name: an internal name used to identify the menu item; defaults to the slugified form of the label. Also applied as a CSS class to the wrapping ``<li>``, as ``"menu-{name}"``.
|
||||
:classnames: additional classnames applied to the link, used to give it an icon
|
||||
:attrs: additional HTML attributes to apply to the link
|
||||
:order: an integer which determines the item's position in the menu
|
||||
|
||||
``MenuItem`` can be subclassed to customise the HTML output, specify Javascript files required by the menu item, or conditionally show or hide the item for specific requests (for example, to apply permission checks); see the source code (``wagtail/wagtailadmin/menu.py``) for details.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
|
@ -540,11 +550,23 @@ The available hooks are:
|
|||
from wagtail.wagtailcore import hooks
|
||||
from wagtail.wagtailadmin.menu import MenuItem
|
||||
|
||||
@hooks.register('register_admin_menu_item')
|
||||
def register_frank_menu_item():
|
||||
return MenuItem('Frank', reverse('frank'), classnames='icon icon-folder-inverse', order=10000)
|
||||
|
||||
.. _construct_main_menu:
|
||||
|
||||
``construct_main_menu``
|
||||
Called just before the Wagtail admin menu is output, to allow the list of menu items to be modified. The callable passed to this hook will receive a ``request`` object and a list of ``menu_items``, and should modify ``menu_items`` in-place as required. Adding menu items should generally be done through the ``register_admin_menu_item`` hook instead - items added through ``construct_main_menu`` will be missing any associated Javascript includes, and their ``is_shown`` check will not be applied.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from wagtail.wagtailcore import hooks
|
||||
|
||||
@hooks.register('construct_main_menu')
|
||||
def construct_main_menu(request, menu_items):
|
||||
menu_items.append(
|
||||
MenuItem( 'Frank', reverse('frank'), classnames='icon icon-folder-inverse', order=10000)
|
||||
)
|
||||
def hide_explorer_menu_item_from_frank(request, menu_items):
|
||||
if request.user.username == 'frank':
|
||||
menu_items[:] = [item for item in menu_items if item.name != 'explorer']
|
||||
|
||||
|
||||
.. _insert_editor_js:
|
||||
|
|
|
|||
|
|
@ -21,4 +21,4 @@ The presentation of your content, the actual webpages, includes the normal use o
|
|||
editing_api
|
||||
advanced_topics/queryset_methods
|
||||
advanced_topics/private_pages
|
||||
advanced_topics/routable_page
|
||||
advanced_topics/routable_page_mixin
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
.. _pages-theory:
|
||||
|
||||
======
|
||||
Theory
|
||||
======
|
||||
|
|
|
|||
|
|
@ -112,13 +112,16 @@ For example:
|
|||
<!-- or a square thumbnail: -->
|
||||
{% image self.photo fill-80x80 %}
|
||||
|
||||
In the above syntax ``[image]`` is the Django object refering to the image. If your page model defined a field called "photo" then ``[image]`` would probably be ``self.photo``. The ``[resize-rule]`` defines how the image is to be resized when inserted into the page; various resizing methods are supported, to cater for different usage cases (e.g. lead images that span the whole width of the page, or thumbnails to be cropped to a fixed size).
|
||||
In the above syntax example ``[image]`` is the Django object refering to the image. If your page model defined a field called "photo" then ``[image]`` would probably be ``self.photo``. The ``[resize-rule]`` defines how the image is to be resized when inserted into the page; various resizing methods are supported, to cater for different usage cases (e.g. lead images that span the whole width of the page, or thumbnails to be cropped to a fixed size).
|
||||
|
||||
Note that a space separates ``[image]`` and ``[resize-rule]``, but the resize rule must not contain spaces.
|
||||
|
||||
|
||||
The available resizing methods are:
|
||||
|
||||
|
||||
.. glossary::
|
||||
|
||||
``max``
|
||||
(takes two dimensions)
|
||||
|
||||
|
|
@ -182,6 +185,7 @@ The available resizing methods are:
|
|||
Leaves the image at its original size - no resizing is performed.
|
||||
|
||||
|
||||
|
||||
.. Note::
|
||||
Wagtail does not allow deforming or stretching images. Image dimension ratios will always be kept. Wagtail also *does not support upscaling*. Small images forced to appear at larger sizes will "max out" at their their native dimensions.
|
||||
|
||||
|
|
@ -218,6 +222,15 @@ Wagtail can assign the image data to another variable using Django's ``as`` synt
|
|||
height="{{ tmp_photo.height }}" alt="{{ tmp_photo.alt }}" class="my-custom-class" />
|
||||
|
||||
|
||||
This syntax exposes the underlying image "Rendition" (``tmp_photo``) to the developer. A "Rendition" contains just the information specific to the way you've requested to format the image i.e dimensions and source URL.
|
||||
|
||||
If your site defines a custom image model using ``AbstractImage``, then any additional fields you add to an image e.g a copyright holder, are **not** part of the image *rendition*, they're part of the image *model*.
|
||||
|
||||
Therefore in the above example, if you'd added the field ``foo`` to your AbstractImage you'd access it using ``{{ self.photo.foo }}`` not ``{{ tmp_photo.foo }}``.
|
||||
|
||||
(Due to the links in the database between renditions and their parent image, you could also access it as ``{{ tmp_photo.image.foo }}`` but this is clearly confusing.)
|
||||
|
||||
|
||||
.. Note::
|
||||
The image property used for the ``src`` attribute is actually ``image.url``, not ``image.src``.
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ For Python developers
|
|||
Basic usage
|
||||
===========
|
||||
|
||||
By default using the :ref:`wagtailsearch_backends_database`, Wagtail's search will only index the ``title`` field of pages.
|
||||
|
||||
All searches are performed on Django QuerySets. Wagtail provides a ``search`` method on the queryset for all page models:
|
||||
|
||||
.. code-block:: python
|
||||
|
|
@ -35,20 +37,20 @@ Indexing extra fields
|
|||
|
||||
The ``indexed_fields`` configuration format was replaced with ``search_fields``
|
||||
|
||||
.. versionchanged:: 0.6
|
||||
|
||||
.. note::
|
||||
|
||||
Searching on extra fields with the database backend is not currently supported.
|
||||
The ``wagtail.wagtailsearch.indexed`` module was renamed to ``wagtail.wagtailsearch.index``
|
||||
|
||||
|
||||
Fields need to be explicitly added to the search configuration in order for you to be able to search/filter on them.
|
||||
.. warning::
|
||||
|
||||
You can add new fields to the search index by overriding the ``search_fields`` property and appending a list of extra ``SearchField``/``FilterField`` objects to it.
|
||||
|
||||
The default value of ``search_fields`` (as set in ``Page``) indexes the ``title`` field as a ``SearchField`` and some other generally useful fields as ``FilterField`` rules.
|
||||
Indexing extra fields is only supported with ElasticSearch as your backend. If you're using the database backend, any other fields you define via ``search_fields`` will be ignored.
|
||||
|
||||
|
||||
Quick example
|
||||
Fields must be explicitly added to the ``search_fields`` property of your ``Page``-derived model, in order for you to be able to search/filter on them. This is done by overriding ``search_fields`` to append a list of extra ``SearchField``/``FilterField`` objects to it.
|
||||
|
||||
|
||||
Example
|
||||
-------------
|
||||
|
||||
This creates an ``EventPage`` model with two fields ``description`` and ``date``. ``description`` is indexed as a ``SearchField`` and ``date`` is indexed as a ``FilterField``
|
||||
|
|
@ -56,15 +58,15 @@ This creates an ``EventPage`` model with two fields ``description`` and ``date``
|
|||
|
||||
.. code-block:: python
|
||||
|
||||
from wagtail.wagtailsearch import indexed
|
||||
from wagtail.wagtailsearch import index
|
||||
|
||||
class EventPage(Page):
|
||||
description = models.TextField()
|
||||
date = models.DateField()
|
||||
|
||||
search_fields = Page.search_fields + ( # Inherit search_fields from Page
|
||||
indexed.SearchField('description'),
|
||||
indexed.FilterField('date'),
|
||||
index.SearchField('description'),
|
||||
index.FilterField('date'),
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -72,7 +74,7 @@ This creates an ``EventPage`` model with two fields ``description`` and ``date``
|
|||
>>> EventPage.objects.filter(date__gt=timezone.now()).search("Christmas")
|
||||
|
||||
|
||||
``indexed.SearchField``
|
||||
``index.SearchField``
|
||||
-----------------------
|
||||
|
||||
These are added to the search index and are used for performing full-text searches on your models. These would usually be text fields.
|
||||
|
|
@ -86,7 +88,7 @@ Options
|
|||
- **es_extra** (dict) - This field is to allow the developer to set or override any setting on the field in the ElasticSearch mapping. Use this if you want to make use of any ElasticSearch features that are not yet supported in Wagtail.
|
||||
|
||||
|
||||
``indexed.FilterField``
|
||||
``index.FilterField``
|
||||
-----------------------
|
||||
|
||||
These are added to the search index but are not used for full-text searches. Instead, they allow you to run filters on your search results.
|
||||
|
|
@ -107,7 +109,7 @@ One use for this is indexing ``get_*_display`` methods Django creates automatica
|
|||
|
||||
.. code-block:: python
|
||||
|
||||
from wagtail.wagtailsearch import indexed
|
||||
from wagtail.wagtailsearch import index
|
||||
|
||||
class EventPage(Page):
|
||||
IS_PRIVATE_CHOICES = (
|
||||
|
|
@ -119,10 +121,10 @@ One use for this is indexing ``get_*_display`` methods Django creates automatica
|
|||
|
||||
search_fields = Page.search_fields + (
|
||||
# Index the human-readable string for searching
|
||||
indexed.SearchField('get_is_private_display'),
|
||||
index.SearchField('get_is_private_display'),
|
||||
|
||||
# Index the boolean value for filtering
|
||||
indexed.FilterField('is_private'),
|
||||
index.FilterField('is_private'),
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -131,25 +133,25 @@ Indexing non-page models
|
|||
|
||||
Any Django model can be indexed and searched.
|
||||
|
||||
To do this, inherit from ``indexed.Indexed`` and add some ``search_fields`` to the model.
|
||||
To do this, inherit from ``index.Indexed`` and add some ``search_fields`` to the model.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from wagtail.wagtailsearch import indexed
|
||||
from wagtail.wagtailsearch import index
|
||||
|
||||
class Book(models.Model, indexed.Indexed):
|
||||
class Book(models.Model, index.Indexed):
|
||||
title = models.CharField(max_length=255)
|
||||
genre = models.CharField(max_length=255, choices=GENRE_CHOICES)
|
||||
author = models.ForeignKey(Author)
|
||||
published_date = models.DateTimeField()
|
||||
|
||||
search_fields = (
|
||||
indexed.SearchField('title', partial_match=True, boost=10),
|
||||
indexed.SearchField('get_genre_display'),
|
||||
index.SearchField('title', partial_match=True, boost=10),
|
||||
index.SearchField('get_genre_display'),
|
||||
|
||||
indexed.FilterField('genre'),
|
||||
indexed.FilterField('author'),
|
||||
indexed.FilterField('published_date'),
|
||||
index.FilterField('genre'),
|
||||
index.FilterField('author'),
|
||||
index.FilterField('published_date'),
|
||||
)
|
||||
|
||||
# As this model doesn't have a search method in its QuerySet, we have to call search directly on the backend
|
||||
|
|
|
|||
10
docs/core_components/sites.rst
Normal file
10
docs/core_components/sites.rst
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
.. _wagtail_site_admin:
|
||||
|
||||
Sites
|
||||
=====
|
||||
|
||||
Django's built-in admin interface provides the way to map a "site" (hostname or domain) to any node in the wagtail tree, using that node as the site's root. See :ref:`pages-theory`.
|
||||
|
||||
Access this by going to ``/django-admin/`` and then "Home › Wagtailcore › Sites." To try out a development site, add a single site with the hostname ``localhost`` at port ``8000`` and map it to one of the pieces of content you have created.
|
||||
|
||||
Wagtail's developers plan to move the site settings into the Wagtail admin interface.
|
||||
|
|
@ -8,4 +8,5 @@ How to
|
|||
settings
|
||||
deploying
|
||||
performance
|
||||
multilingual_sites
|
||||
contributing
|
||||
|
|
|
|||
146
docs/howto/multilingual_sites.rst
Normal file
146
docs/howto/multilingual_sites.rst
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
===========================
|
||||
Creating multilingual sites
|
||||
===========================
|
||||
|
||||
This tutorial will show you a method of creating multilingual sites in Wagtail.
|
||||
|
||||
Currently, Wagtail doesn't support multiple languages in the same page. The recommended way of creating multilingual websites in Wagtail at the moment is to create one section of your website for each language.
|
||||
|
||||
For example::
|
||||
|
||||
/
|
||||
en/
|
||||
about/
|
||||
contact/
|
||||
fr/
|
||||
about/
|
||||
contact/
|
||||
|
||||
|
||||
The root page
|
||||
=============
|
||||
|
||||
The root page (``/``) should detect the browsers language and forward them to the correct language homepage (``/en/``, ``/fr/``). This page should sit at the site root (where the homepage would normally be).
|
||||
|
||||
We must set Djangos ``LANGUAGES`` setting so we don't redirect non English/French users to pages that don't exist.
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# settings.py
|
||||
LANGUAGES = (
|
||||
('en', _("English")),
|
||||
('fr', _("French")),
|
||||
)
|
||||
|
||||
# models.py
|
||||
from django.utils import translation
|
||||
from django.http import HttpResponseRedirect
|
||||
|
||||
from wagtail.wagtailcore.models import Page
|
||||
|
||||
|
||||
class LanguageRedirectionPage(Page):
|
||||
|
||||
def serve(self, request):
|
||||
# This will only return a language that is in the LANGUAGES Django setting
|
||||
language = translation.get_language_from_request(request)
|
||||
|
||||
return HttpResponseRedirect(self.url + language + '/')
|
||||
|
||||
|
||||
Linking pages together
|
||||
======================
|
||||
|
||||
It may be useful to link different versions of the same page together to allow the user to easily switch between languages. But we don't want to increse the burdon on the editor too much so ideally, editors should only need to link one of the pages to the other versions and the links between the other versions should be created implicitly.
|
||||
|
||||
As this behaviour needs to be added to all page types that would be translated, its best to put this behaviour in a mixin.
|
||||
|
||||
Heres an example of how this could be implemented (with English as the main language and French/Spanish as alternative languages):
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class TranslatablePageMixin(models.Model):
|
||||
# One link for each alternative language
|
||||
# These should only be used on the main language page (english)
|
||||
french_link = models.ForeignKey(Page, null=True, on_delete=models.SET_NULL, blank=True, related_name='+')
|
||||
spanish_link = models.ForeignKey(Page, null=True, on_delete=models.SET_NULL, blank=True, related_name='+')
|
||||
|
||||
def get_language(self):
|
||||
"""
|
||||
This returns the language code for this page.
|
||||
"""
|
||||
# Look through ancestors of this page for its language homepage
|
||||
# The language homepage is located at depth 3
|
||||
language_homepage = self.get_ancestors(inclusive=True).get(depth=3)
|
||||
|
||||
# The slug of language homepages should always be set to the language code
|
||||
return language_homepage.slug
|
||||
|
||||
|
||||
# Method to find the main language version of this page
|
||||
# This works by reversing the above links
|
||||
|
||||
def english_page(self):
|
||||
"""
|
||||
This finds the english version of this page
|
||||
"""
|
||||
language = self.get_language()
|
||||
|
||||
if language == 'en':
|
||||
return self
|
||||
elif language == 'fr':
|
||||
return type(self).objects.filter(french_link=self).first().specific
|
||||
elif language == 'es':
|
||||
return type(self).objects.filter(spanish_link=self).first().specific
|
||||
|
||||
|
||||
# We need a method to find a version of this page for each alternative language.
|
||||
# These all work the same way. They firstly find the main version of the page
|
||||
# (english), then from there they can just follow the link to the correct page.
|
||||
|
||||
def french_page(self):
|
||||
"""
|
||||
This finds the french version of this page
|
||||
"""
|
||||
english_page = self.english_page()
|
||||
|
||||
if english_page and english_page.french_link:
|
||||
return english_page.french_link.specific
|
||||
|
||||
def spanish_page(self):
|
||||
"""
|
||||
This finds the spanish version of this page
|
||||
"""
|
||||
english_page = self.english_page()
|
||||
|
||||
if english_page and english_page.spanish_link:
|
||||
return english_page.spanish_link.specific
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
|
||||
class AboutPage(Page, TranslatablePageMixin):
|
||||
...
|
||||
|
||||
|
||||
class ContactPage(Page, TranslatablePageMixin):
|
||||
...
|
||||
|
||||
|
||||
You can make use of these methods in your template by doing:
|
||||
|
||||
.. code-block:: django
|
||||
|
||||
{% if self.english_page and self.get_language != 'en' %}
|
||||
<a href="{{ self.english_page.url }}">{% trans "View in English" %}</a>
|
||||
{% endif %}
|
||||
|
||||
{% if self.french_page and self.get_language != 'fr' %}
|
||||
<a href="{{ self.french_page.url }}">{% trans "View in French" %}</a>
|
||||
{% endif %}
|
||||
|
||||
{% if self.spanish_page and self.get_language != 'es' %}
|
||||
<a href="{{ self.spanish_page.url }}">{% trans "View in Spanish" %}</a>
|
||||
{% endif %}
|
||||
|
|
@ -3,7 +3,7 @@ Welcome to Wagtail's documentation
|
|||
|
||||
Wagtail is a modern, flexible CMS, built on Django.
|
||||
|
||||
It supports Django 1.6.2+ on Python 2.6, 2.7, 3.2, 3.3 and 3.4. Django 1.7 support is in progress pending further release candidate testing.
|
||||
It supports Django 1.6.2+ and 1.7rc3+ on Python 2.6, 2.7, 3.2, 3.3 and 3.4.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
|
|
|
|||
|
|
@ -158,6 +158,8 @@ The scheduled publishing mechanism adds an ``expired`` field to wagtailcore.Page
|
|||
'expired': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
|
||||
|
||||
.. _04_deprecated_features:
|
||||
|
||||
Deprecated features
|
||||
===================
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ RoutablePage
|
|||
|
||||
A ``RoutablePage`` model has been added to allow embedding Django-style URL routing within a page.
|
||||
|
||||
:ref:`routable_page`
|
||||
:ref:`routable_page_mixin`
|
||||
|
||||
|
||||
Usage stats for images, documents and snippets
|
||||
|
|
@ -129,4 +129,4 @@ South upgraded to 1.0
|
|||
|
||||
In preparation for Django 1.7 support in a future release, Wagtail now depends on South 1.0, and its migration files have been moved from ``migrations`` to ``south_migrations``. Older versions of South will fail to find the migrations in the new location.
|
||||
|
||||
If your project's requirements file (most commonly requirements.txt or requirements/base.txt) references a specific older version of South, this must be updated to South 1.0.
|
||||
If your project's requirements file (most commonly requirements.txt or requirements/base.txt) references a specific older version of South, this must be updated to South 1.0.
|
||||
|
|
|
|||
|
|
@ -10,13 +10,40 @@ Wagtail 0.6 release notes - IN DEVELOPMENT
|
|||
What's new
|
||||
==========
|
||||
|
||||
Django 1.7 support
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Wagtail can now be used with Django 1.7.
|
||||
|
||||
|
||||
Minor features
|
||||
~~~~~~~~~~~~~~
|
||||
* A new template tag has been added for reversing URLs inside routable pages. See :ref:`routablepageurl_template_tag`.
|
||||
* RoutablePage can now be used as a mixin. See :class:`wagtail.contrib.wagtailroutablepage.models.RoutablePageMixin`.
|
||||
* MenuItems can now have bundled JavaScript
|
||||
* Added a new hook for registering admin menu items. See :ref:`register_admin_menu_item`
|
||||
|
||||
|
||||
Bug fixes
|
||||
~~~~~~~~~
|
||||
|
||||
* Page URL generation now returns correct URLs for sites that have the main 'serve' view rooted somewhere other than '/'.
|
||||
* Search results in the page chooser now respect the page_type parameter on PageChooserPanel.
|
||||
* Rendition filenames are now prevented from going over 60 chars, even with a large focal_point_key.
|
||||
* Child relations that are defined on a model's superclass (such as the base Page model) are now picked up correctly by the page editing form, page copy operations and the replace_text management command.
|
||||
|
||||
|
||||
Upgrade considerations
|
||||
======================
|
||||
|
||||
All features deprecated in 0.4 have been removed
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
See: :ref:`04_deprecated_features`
|
||||
|
||||
|
||||
Deprecated features
|
||||
===================
|
||||
|
||||
* The ``wagtail.wagtailsearch.indexed`` module has been renamed to ``wagtail.wagtailsearch.index``
|
||||
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
import sys
|
||||
import os
|
||||
import shutil
|
||||
import warnings
|
||||
|
||||
from django.core.management import execute_from_command_line
|
||||
|
||||
|
|
@ -12,6 +13,9 @@ os.environ['DJANGO_SETTINGS_MODULE'] = 'wagtail.tests.settings'
|
|||
|
||||
|
||||
def runtests():
|
||||
# Don't ignore DeprecationWarnings
|
||||
warnings.simplefilter('default', DeprecationWarning)
|
||||
|
||||
argv = sys.argv[:1] + ['test'] + sys.argv[1:]
|
||||
try:
|
||||
execute_from_command_line(argv)
|
||||
|
|
|
|||
6
setup.py
6
setup.py
|
|
@ -23,12 +23,12 @@ PY3 = sys.version_info[0] == 3
|
|||
|
||||
|
||||
install_requires = [
|
||||
"Django>=1.6.2,<1.7",
|
||||
"Django>=1.6.2,<1.8",
|
||||
"South==1.0.0",
|
||||
"django-compressor>=1.4",
|
||||
"django-libsass>=0.2",
|
||||
"django-modelcluster>=0.3",
|
||||
"django-taggit==0.12.0",
|
||||
"django-modelcluster>=0.4",
|
||||
"django-taggit==0.12.1",
|
||||
"django-treebeard==2.0",
|
||||
"Pillow>=2.3.0",
|
||||
"beautifulsoup4>=4.3.2",
|
||||
|
|
|
|||
157
tox.ini
157
tox.ini
|
|
@ -1,11 +1,40 @@
|
|||
[deps]
|
||||
dj16=
|
||||
Django>=1.6,<1.7
|
||||
base =
|
||||
South==1.0.0
|
||||
django-compressor>=1.4
|
||||
django-libsass>=0.2
|
||||
django-modelcluster>=0.3
|
||||
django-taggit==0.12.1
|
||||
django-treebeard==2.0
|
||||
Pillow>=2.3.0
|
||||
beautifulsoup4>=4.3.2
|
||||
html5lib==0.999
|
||||
Unidecode>=0.04.14
|
||||
six==1.7.3
|
||||
requests==2.3.0
|
||||
elasticsearch==1.1.0
|
||||
mock==1.0.1
|
||||
python-dateutil==2.2
|
||||
Embedly
|
||||
coverage
|
||||
|
||||
dj16 =
|
||||
Django>=1.6,<1.7
|
||||
|
||||
|
||||
dj17 =
|
||||
https://github.com/django/django/archive/stable/1.7.x.zip#egg=django
|
||||
|
||||
py2 =
|
||||
unicodecsv>=0.9.4
|
||||
|
||||
py3 =
|
||||
|
||||
|
||||
[tox]
|
||||
skipsdist = True
|
||||
usedevelop = True
|
||||
|
||||
envlist =
|
||||
py26-dj16-postgres,
|
||||
py26-dj16-sqlite,
|
||||
|
|
@ -13,7 +42,16 @@ envlist =
|
|||
py27-dj16-sqlite,
|
||||
py32-dj16-postgres,
|
||||
py33-dj16-postgres,
|
||||
py34-dj16-postgres
|
||||
py34-dj16-postgres,
|
||||
|
||||
py27-dj17-postgres,
|
||||
py27-dj17-sqlite,
|
||||
py32-dj17-postgres,
|
||||
py32-dj17-sqlite,
|
||||
py33-dj17-postgres,
|
||||
py33-dj17-sqlite,
|
||||
py34-dj17-postgres,
|
||||
py34-dj17-sqlite
|
||||
|
||||
# mysql not currently supported
|
||||
# (wagtail.wagtailimages.tests.TestImageEditView currently fails with a
|
||||
|
|
@ -28,11 +66,13 @@ envlist =
|
|||
|
||||
|
||||
[testenv]
|
||||
commands=./runtests.py
|
||||
commands=coverage run runtests.py
|
||||
|
||||
[testenv:py26-dj16-postgres]
|
||||
basepython=python2.6
|
||||
deps =
|
||||
{[deps]base}
|
||||
{[deps]py2}
|
||||
{[deps]dj16}
|
||||
psycopg2==2.5.3
|
||||
setenv =
|
||||
|
|
@ -41,6 +81,8 @@ setenv =
|
|||
[testenv:py26-dj16-sqlite]
|
||||
basepython=python2.6
|
||||
deps =
|
||||
{[deps]base}
|
||||
{[deps]py2}
|
||||
{[deps]dj16}
|
||||
setenv =
|
||||
DATABASE_ENGINE=django.db.backends.sqlite3
|
||||
|
|
@ -48,6 +90,8 @@ setenv =
|
|||
[testenv:py26-dj16-mysql]
|
||||
basepython=python2.6
|
||||
deps =
|
||||
{[deps]base}
|
||||
{[deps]py2}
|
||||
{[deps]dj16}
|
||||
MySQL-python==1.2.5
|
||||
setenv =
|
||||
|
|
@ -57,6 +101,8 @@ setenv =
|
|||
[testenv:py27-dj16-postgres]
|
||||
basepython=python2.7
|
||||
deps =
|
||||
{[deps]base}
|
||||
{[deps]py2}
|
||||
{[deps]dj16}
|
||||
psycopg2==2.5.3
|
||||
setenv =
|
||||
|
|
@ -65,6 +111,8 @@ setenv =
|
|||
[testenv:py27-dj16-sqlite]
|
||||
basepython=python2.7
|
||||
deps =
|
||||
{[deps]base}
|
||||
{[deps]py2}
|
||||
{[deps]dj16}
|
||||
setenv =
|
||||
DATABASE_ENGINE=django.db.backends.sqlite3
|
||||
|
|
@ -72,6 +120,8 @@ setenv =
|
|||
[testenv:py27-dj16-mysql]
|
||||
basepython=python2.7
|
||||
deps =
|
||||
{[deps]base}
|
||||
{[deps]py2}
|
||||
{[deps]dj16}
|
||||
MySQL-python==1.2.5
|
||||
setenv =
|
||||
|
|
@ -81,6 +131,8 @@ setenv =
|
|||
[testenv:py32-dj16-postgres]
|
||||
basepython=python3.2
|
||||
deps =
|
||||
{[deps]base}
|
||||
{[deps]py3}
|
||||
{[deps]dj16}
|
||||
psycopg2==2.5.3
|
||||
setenv =
|
||||
|
|
@ -89,6 +141,8 @@ setenv =
|
|||
[testenv:py32-dj16-sqlite]
|
||||
basepython=python3.2
|
||||
deps =
|
||||
{[deps]base}
|
||||
{[deps]py3}
|
||||
{[deps]dj16}
|
||||
setenv =
|
||||
DATABASE_ENGINE=django.db.backends.sqlite3
|
||||
|
|
@ -96,6 +150,8 @@ setenv =
|
|||
[testenv:py33-dj16-postgres]
|
||||
basepython=python3.3
|
||||
deps =
|
||||
{[deps]base}
|
||||
{[deps]py3}
|
||||
{[deps]dj16}
|
||||
psycopg2==2.5.3
|
||||
setenv =
|
||||
|
|
@ -104,6 +160,8 @@ setenv =
|
|||
[testenv:py33-dj16-sqlite]
|
||||
basepython=python3.3
|
||||
deps =
|
||||
{[deps]base}
|
||||
{[deps]py3}
|
||||
{[deps]dj16}
|
||||
setenv =
|
||||
DATABASE_ENGINE=django.db.backends.sqlite3
|
||||
|
|
@ -111,6 +169,8 @@ setenv =
|
|||
[testenv:py34-dj16-postgres]
|
||||
basepython=python3.4
|
||||
deps =
|
||||
{[deps]base}
|
||||
{[deps]py3}
|
||||
{[deps]dj16}
|
||||
psycopg2==2.5.3
|
||||
setenv =
|
||||
|
|
@ -119,6 +179,95 @@ setenv =
|
|||
[testenv:py34-dj16-sqlite]
|
||||
basepython=python3.4
|
||||
deps =
|
||||
{[deps]base}
|
||||
{[deps]py3}
|
||||
{[deps]dj16}
|
||||
setenv =
|
||||
DATABASE_ENGINE=django.db.backends.sqlite3
|
||||
|
||||
[testenv:py27-dj17-postgres]
|
||||
basepython=python2.7
|
||||
deps =
|
||||
{[deps]base}
|
||||
{[deps]py2}
|
||||
{[deps]dj17}
|
||||
psycopg2==2.5.3
|
||||
setenv =
|
||||
DATABASE_ENGINE=django.db.backends.postgresql_psycopg2
|
||||
|
||||
[testenv:py27-dj17-sqlite]
|
||||
basepython=python2.7
|
||||
deps =
|
||||
{[deps]base}
|
||||
{[deps]py2}
|
||||
{[deps]dj17}
|
||||
setenv =
|
||||
DATABASE_ENGINE=django.db.backends.sqlite3
|
||||
|
||||
[testenv:py27-dj17-mysql]
|
||||
basepython=python2.7
|
||||
deps =
|
||||
{[deps]base}
|
||||
{[deps]py2}
|
||||
{[deps]dj17}
|
||||
MySQL-python==1.2.5
|
||||
setenv =
|
||||
DATABASE_ENGINE=django.db.backends.mysql
|
||||
DATABASE_USER=wagtail
|
||||
|
||||
[testenv:py32-dj17-postgres]
|
||||
basepython=python3.2
|
||||
deps =
|
||||
{[deps]base}
|
||||
{[deps]py3}
|
||||
{[deps]dj17}
|
||||
psycopg2==2.5.3
|
||||
setenv =
|
||||
DATABASE_ENGINE=django.db.backends.postgresql_psycopg2
|
||||
|
||||
[testenv:py32-dj17-sqlite]
|
||||
basepython=python3.2
|
||||
deps =
|
||||
{[deps]base}
|
||||
{[deps]py3}
|
||||
{[deps]dj17}
|
||||
setenv =
|
||||
DATABASE_ENGINE=django.db.backends.sqlite3
|
||||
|
||||
[testenv:py33-dj17-postgres]
|
||||
basepython=python3.3
|
||||
deps =
|
||||
{[deps]base}
|
||||
{[deps]py3}
|
||||
{[deps]dj17}
|
||||
psycopg2==2.5.3
|
||||
setenv =
|
||||
DATABASE_ENGINE=django.db.backends.postgresql_psycopg2
|
||||
|
||||
[testenv:py33-dj17-sqlite]
|
||||
basepython=python3.3
|
||||
deps =
|
||||
{[deps]base}
|
||||
{[deps]py3}
|
||||
{[deps]dj17}
|
||||
setenv =
|
||||
DATABASE_ENGINE=django.db.backends.sqlite3
|
||||
|
||||
[testenv:py34-dj17-postgres]
|
||||
basepython=python3.4
|
||||
deps =
|
||||
{[deps]base}
|
||||
{[deps]py3}
|
||||
{[deps]dj17}
|
||||
psycopg2==2.5.3
|
||||
setenv =
|
||||
DATABASE_ENGINE=django.db.backends.postgresql_psycopg2
|
||||
|
||||
[testenv:py34-dj17-sqlite]
|
||||
basepython=python3.4
|
||||
deps =
|
||||
{[deps]base}
|
||||
{[deps]py3}
|
||||
{[deps]dj17}
|
||||
setenv =
|
||||
DATABASE_ENGINE=django.db.backends.sqlite3
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
default_app_config = 'wagtail.contrib.wagtailfrontendcache.apps.WagtailFrontendCacheAppConfig'
|
||||
7
wagtail/contrib/wagtailfrontendcache/apps.py
Normal file
7
wagtail/contrib/wagtailfrontendcache/apps.py
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class WagtailFrontendCacheAppConfig(AppConfig):
|
||||
name = 'wagtail.contrib.wagtailfrontendcache'
|
||||
label = 'wagtailfrontendcache'
|
||||
verbose_name = "Wagtail frontend cache"
|
||||
|
|
@ -0,0 +1 @@
|
|||
default_app_config = 'wagtail.contrib.wagtailmedusa.apps.WagtailMedusaAppConfig'
|
||||
7
wagtail/contrib/wagtailmedusa/apps.py
Normal file
7
wagtail/contrib/wagtailmedusa/apps.py
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class WagtailMedusaAppConfig(AppConfig):
|
||||
name = 'wagtail.contrib.wagtailmedusa'
|
||||
label = 'wagtailmedusa'
|
||||
verbose_name = "Wagtail medusa"
|
||||
|
|
@ -0,0 +1 @@
|
|||
default_app_config = 'wagtail.contrib.wagtailroutablepage.apps.WagtailRoutablePageAppConfig'
|
||||
7
wagtail/contrib/wagtailroutablepage/apps.py
Normal file
7
wagtail/contrib/wagtailroutablepage/apps.py
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class WagtailRoutablePageAppConfig(AppConfig):
|
||||
name = 'wagtail.contrib.wagtailroutablepage'
|
||||
label = 'wagtailroutablepage'
|
||||
verbose_name = "Wagtail routablepage"
|
||||
|
|
@ -8,9 +8,10 @@ from wagtail.wagtailcore.models import Page
|
|||
from wagtail.wagtailcore.url_routing import RouteResult
|
||||
|
||||
|
||||
class RoutablePage(Page):
|
||||
class RoutablePageMixin(object):
|
||||
"""
|
||||
This class extends Page by adding methods to allow urlconfs to be embedded inside pages
|
||||
This class can be mixed in to a Page subclass to allow urlconfs to be
|
||||
embedded inside pages.
|
||||
"""
|
||||
#: Set this to a tuple of ``django.conf.urls.url`` objects.
|
||||
subpage_urls = None
|
||||
|
|
@ -59,7 +60,7 @@ class RoutablePage(Page):
|
|||
except Http404:
|
||||
pass
|
||||
|
||||
return super(RoutablePage, self).route(request, path_components)
|
||||
return super(RoutablePageMixin, self).route(request, path_components)
|
||||
|
||||
def serve(self, request, view, args, kwargs):
|
||||
return view(request, *args, **kwargs)
|
||||
|
|
@ -68,6 +69,13 @@ class RoutablePage(Page):
|
|||
view, args, kwargs = self.resolve_subpage('/')
|
||||
return view(*args, **kwargs)
|
||||
|
||||
|
||||
class RoutablePage(RoutablePageMixin, Page):
|
||||
"""
|
||||
This class extends Page by adding methods to allow urlconfs
|
||||
to be embedded inside pages
|
||||
"""
|
||||
|
||||
is_abstract = True
|
||||
|
||||
class Meta:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
from django import template
|
||||
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.simple_tag(takes_context=True)
|
||||
def routablepageurl(context, page, url_name, *args, **kwargs):
|
||||
"""
|
||||
``routablepageurl`` is similar to ``pageurl``, but works with
|
||||
``RoutablePage``\s. It behaves like a hybrid between the built-in
|
||||
``reverse``, and ``pageurl`` from Wagtail.
|
||||
|
||||
``page`` is the RoutablePage that URLs will be generated from.
|
||||
|
||||
``url_name`` is a URL name defined in ``page.subpage_urls``.
|
||||
|
||||
Positional arguments and keyword arguments should be passed as normal
|
||||
positional arguments and keyword arguments.
|
||||
"""
|
||||
request = context['request']
|
||||
base_url = page.relative_url(request.site)
|
||||
routed_url = page.reverse_subpage(url_name, args=args, kwargs=kwargs)
|
||||
return base_url + routed_url
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
from django.test import TestCase
|
||||
from django.test import TestCase, RequestFactory
|
||||
|
||||
from wagtail.wagtailcore.models import Page
|
||||
from wagtail.wagtailcore.models import Page, Site
|
||||
from wagtail.tests.models import RoutablePageTest, routable_page_external_view
|
||||
from wagtail.contrib.wagtailroutablepage.templatetags.wagtailroutablepage_tags import routablepageurl
|
||||
|
||||
|
||||
class TestRoutablePage(TestCase):
|
||||
|
|
@ -80,3 +81,35 @@ class TestRoutablePage(TestCase):
|
|||
response = self.client.get(self.routable_page.url + 'external/joe-bloggs/')
|
||||
|
||||
self.assertContains(response, "EXTERNAL VIEW: joe-bloggs")
|
||||
|
||||
|
||||
class TestRoutablePageTemplateTag(TestRoutablePage):
|
||||
def setUp(self):
|
||||
super(TestRoutablePageTemplateTag, self).setUp()
|
||||
self.rf = RequestFactory()
|
||||
self.request = self.rf.get(self.routable_page.url)
|
||||
self.request.site = Site.find_for_request(self.request)
|
||||
self.context = {'request': self.request}
|
||||
|
||||
def test_templatetag_reverse_main_view(self):
|
||||
url = routablepageurl(self.context, self.routable_page,
|
||||
'main')
|
||||
self.assertEqual(url, self.routable_page.url)
|
||||
|
||||
def test_templatetag_reverse_archive_by_year_view(self):
|
||||
url = routablepageurl(self.context, self.routable_page,
|
||||
'archive_by_year', '2014')
|
||||
|
||||
self.assertEqual(url, self.routable_page.url + 'archive/year/2014/')
|
||||
|
||||
def test_templatetag_reverse_archive_by_author_view(self):
|
||||
url = routablepageurl(self.context, self.routable_page,
|
||||
'archive_by_author', author_slug='joe-bloggs')
|
||||
|
||||
self.assertEqual(url, self.routable_page.url + 'archive/author/joe-bloggs/')
|
||||
|
||||
def test_templatetag_reverse_external_view(self):
|
||||
url = routablepageurl(self.context, self.routable_page,
|
||||
'external_view', 'joe-bloggs')
|
||||
|
||||
self.assertEqual(url, self.routable_page.url + 'external/joe-bloggs/')
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
default_app_config = 'wagtail.contrib.wagtailsitemaps.apps.WagtailSitemapsAppConfig'
|
||||
7
wagtail/contrib/wagtailsitemaps/apps.py
Normal file
7
wagtail/contrib/wagtailsitemaps/apps.py
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class WagtailSitemapsAppConfig(AppConfig):
|
||||
name = 'wagtail.contrib.wagtailsitemaps'
|
||||
label = 'wagtailsitemaps'
|
||||
verbose_name = "Wagtail sitemaps"
|
||||
|
|
@ -0,0 +1 @@
|
|||
default_app_config = 'wagtail.contrib.wagtailstyleguide.apps.WagtailStyleGuideAppConfig'
|
||||
7
wagtail/contrib/wagtailstyleguide/apps.py
Normal file
7
wagtail/contrib/wagtailstyleguide/apps.py
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class WagtailStyleGuideAppConfig(AppConfig):
|
||||
name = 'wagtail.contrib.wagtailstyleguide'
|
||||
label = 'wagtailstyleguide'
|
||||
verbose_name = "Wagtail style guide"
|
||||
|
|
@ -30,6 +30,7 @@
|
|||
<li><a href="#editor">Page editor</a></li>
|
||||
<li><a href="#tabs">Tabs</a></li>
|
||||
<li><a href="#breadcrumbs">Breadcrumbs</a></li>
|
||||
<li><a href="#progress">Progress indicators</a></li>
|
||||
<li><a href="#misc">Misc formatters</a></li>
|
||||
<li><a href="#icons">Icons</a></li>
|
||||
</ul>
|
||||
|
|
@ -406,6 +407,20 @@
|
|||
|
||||
</section>
|
||||
|
||||
<section id="progress">
|
||||
<h2>Progress indicators</h2>
|
||||
|
||||
<div id="progress-example" class="progress active">
|
||||
<div class="bar">60%</div>
|
||||
</div>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<div id="progress-example2" class="progress active">
|
||||
<div class="bar" style="width: 50%;">50%</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="misc">
|
||||
<h2>Misc formatters</h2>
|
||||
<h3>Avatar icons</h3>
|
||||
|
|
@ -506,7 +521,16 @@
|
|||
{% block extra_js %}
|
||||
<script>
|
||||
$(function(){
|
||||
|
||||
(function runprogress(){
|
||||
var to = setTimeout(function(){
|
||||
runprogress();
|
||||
clearTimeout(to);
|
||||
var to2 = setTimeout(function(){
|
||||
$('#progress-example .bar').css('width', '20%');
|
||||
}, 2000);
|
||||
}, 3000);
|
||||
$('#progress-example .bar').css('width', '80%');
|
||||
})();
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
@ -15,8 +15,6 @@ def register_admin_urls():
|
|||
]
|
||||
|
||||
|
||||
@hooks.register('construct_main_menu')
|
||||
def construct_main_menu(request, menu_items):
|
||||
menu_items.append(
|
||||
MenuItem(_('Styleguide'), urlresolvers.reverse('wagtailstyleguide'), classnames='icon icon-image', order=1000)
|
||||
)
|
||||
@hooks.register('register_admin_menu_item')
|
||||
def register_styleguide_menu_item():
|
||||
return MenuItem(_('Styleguide'), urlresolvers.reverse('wagtailstyleguide'), classnames='icon icon-image', order=1000)
|
||||
|
|
|
|||
16
wagtail/tests/fixtures/test.json
vendored
16
wagtail/tests/fixtures/test.json
vendored
|
|
@ -90,8 +90,8 @@
|
|||
"model": "tests.eventpagespeaker",
|
||||
"fields": {
|
||||
"page": 4,
|
||||
"first_name": "Santa",
|
||||
"last_name": "Claus",
|
||||
"first_name": "Father",
|
||||
"last_name": "Christmas",
|
||||
"sort_order": 0
|
||||
}
|
||||
},
|
||||
|
|
@ -567,7 +567,17 @@
|
|||
"model": "tests.AdvertPlacement",
|
||||
"fields": {
|
||||
"page": 2,
|
||||
"advert": 1
|
||||
"advert": 1,
|
||||
"colour": "yellow"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 2,
|
||||
"model": "tests.AdvertPlacement",
|
||||
"fields": {
|
||||
"page": 4,
|
||||
"advert": 1,
|
||||
"colour": "greener than a Christmas tree"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
|||
36
wagtail/tests/migrations/0001_initial.py
Normal file
36
wagtail/tests/migrations/0001_initial.py
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('auth', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='CustomUser',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
||||
('last_login', models.DateTimeField(default=django.utils.timezone.now, verbose_name='last login')),
|
||||
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
||||
('username', models.CharField(unique=True, max_length=100)),
|
||||
('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)),
|
||||
('groups', models.ManyToManyField(to='auth.Group', verbose_name='groups', blank=True)),
|
||||
('user_permissions', models.ManyToManyField(to='auth.Permission', verbose_name='user permissions', blank=True)),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
]
|
||||
386
wagtail/tests/migrations/0002_auto_20140827_0908.py
Normal file
386
wagtail/tests/migrations/0002_auto_20140827_0908.py
Normal file
|
|
@ -0,0 +1,386 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
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
|
||||
import modelcluster.tags
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wagtailcore', '0002_initial_data'),
|
||||
('wagtaildocs', '0002_initial_data'),
|
||||
('taggit', '0001_initial'),
|
||||
('wagtailimages', '0002_initial_data'),
|
||||
('tests', '0001_initial'),
|
||||
]
|
||||
|
||||
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)),
|
||||
('text', models.CharField(max_length=255)),
|
||||
],
|
||||
options={
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='AdvertPlacement',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
|
||||
('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)),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
bases=('wagtailcore.page',),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='BusinessIndex',
|
||||
fields=[
|
||||
('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
bases=('wagtailcore.page',),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='BusinessSubIndex',
|
||||
fields=[
|
||||
('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
bases=('wagtailcore.page',),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='EventIndex',
|
||||
fields=[
|
||||
('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)),
|
||||
('intro', wagtail.wagtailcore.fields.RichTextField(blank=True)),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
bases=('wagtailcore.page',),
|
||||
),
|
||||
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')),
|
||||
('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)),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
bases=('wagtailcore.page',),
|
||||
),
|
||||
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)),
|
||||
('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)),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
'ordering': ['sort_order'],
|
||||
},
|
||||
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)),
|
||||
('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)),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
'ordering': ['sort_order'],
|
||||
},
|
||||
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)),
|
||||
('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)),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
'ordering': ['sort_order'],
|
||||
},
|
||||
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)),
|
||||
('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)),
|
||||
('help_text', models.CharField(blank=True, max_length=255)),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
'ordering': ['sort_order'],
|
||||
},
|
||||
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)),
|
||||
('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)),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
bases=('wagtailcore.page',),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='PageWithOldStyleRouteMethod',
|
||||
fields=[
|
||||
('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)),
|
||||
('content', models.TextField()),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
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)),
|
||||
('content', models.TextField()),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
bases=('wagtailcore.page',),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='StandardChild',
|
||||
fields=[
|
||||
('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
bases=('wagtailcore.page',),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='StandardIndex',
|
||||
fields=[
|
||||
('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
bases=('wagtailcore.page',),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='TaggedPage',
|
||||
fields=[
|
||||
('page_ptr', models.OneToOneField(parent_link=True, to='wagtailcore.Page', serialize=False, auto_created=True, primary_key=True)),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
bases=('wagtailcore.page',),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='TaggedPageTag',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, verbose_name='ID', primary_key=True, serialize=False)),
|
||||
('content_object', modelcluster.fields.ParentalKey(to='tests.TaggedPage', related_name='tagged_items')),
|
||||
('tag', models.ForeignKey(to='taggit.Tag', related_name='tests_taggedpagetag_items')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
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.'),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='formfield',
|
||||
name='page',
|
||||
field=modelcluster.fields.ParentalKey(to='tests.FormPage', related_name='form_fields'),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='eventpagespeaker',
|
||||
name='link_page',
|
||||
field=models.ForeignKey(related_name='+', blank=True, to='wagtailcore.Page', null=True),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='eventpagespeaker',
|
||||
name='page',
|
||||
field=modelcluster.fields.ParentalKey(to='tests.EventPage', related_name='speakers'),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='eventpagerelatedlink',
|
||||
name='link_page',
|
||||
field=models.ForeignKey(related_name='+', blank=True, to='wagtailcore.Page', null=True),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='eventpagerelatedlink',
|
||||
name='page',
|
||||
field=modelcluster.fields.ParentalKey(to='tests.EventPage', related_name='related_links'),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='eventpagecarouselitem',
|
||||
name='link_page',
|
||||
field=models.ForeignKey(related_name='+', blank=True, to='wagtailcore.Page', null=True),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='eventpagecarouselitem',
|
||||
name='page',
|
||||
field=modelcluster.fields.ParentalKey(to='tests.EventPage', related_name='carousel_items'),
|
||||
preserve_default=True,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='advertplacement',
|
||||
name='page',
|
||||
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.'),
|
||||
),
|
||||
]
|
||||
20
wagtail/tests/migrations/0003_auto_20140905_0634.py
Normal file
20
wagtail/tests/migrations/0003_auto_20140905_0634.py
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# -*- 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,
|
||||
),
|
||||
]
|
||||
0
wagtail/tests/migrations/__init__.py
Normal file
0
wagtail/tests/migrations/__init__.py
Normal file
|
|
@ -17,7 +17,7 @@ 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.wagtailsearch import indexed
|
||||
from wagtail.wagtailsearch import index
|
||||
from wagtail.contrib.wagtailroutablepage.models import RoutablePage
|
||||
|
||||
|
||||
|
|
@ -228,8 +228,11 @@ class EventPage(Page):
|
|||
related_name='+'
|
||||
)
|
||||
|
||||
indexed_fields = ('get_audience_display', 'location', 'body')
|
||||
search_name = "Event"
|
||||
search_fields = (
|
||||
index.SearchField('get_audience_display'),
|
||||
index.SearchField('location'),
|
||||
index.SearchField('body'),
|
||||
)
|
||||
|
||||
password_required_template = 'tests/event_page_password_required.html'
|
||||
|
||||
|
|
@ -330,6 +333,7 @@ FormPage.content_panels = [
|
|||
class AdvertPlacement(models.Model):
|
||||
page = ParentalKey('wagtailcore.Page', related_name='advert_placements')
|
||||
advert = models.ForeignKey('tests.Advert', related_name='+')
|
||||
colour = models.CharField(max_length=255)
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Advert(models.Model):
|
||||
|
|
@ -374,6 +378,12 @@ class ZuluSnippet(models.Model):
|
|||
class StandardIndex(Page):
|
||||
pass
|
||||
|
||||
StandardIndex.content_panels = [
|
||||
FieldPanel('title', classname="full title"),
|
||||
InlinePanel(StandardIndex, 'advert_placements', label="Adverts"),
|
||||
]
|
||||
|
||||
|
||||
class StandardChild(Page):
|
||||
pass
|
||||
|
||||
|
|
@ -387,19 +397,19 @@ class BusinessChild(Page):
|
|||
subpage_types = []
|
||||
|
||||
|
||||
class SearchTest(models.Model, indexed.Indexed):
|
||||
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 = [
|
||||
indexed.SearchField('title', partial_match=True),
|
||||
indexed.SearchField('content'),
|
||||
indexed.SearchField('callable_indexed_field'),
|
||||
indexed.FilterField('title'),
|
||||
indexed.FilterField('live'),
|
||||
indexed.FilterField('published_date'),
|
||||
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):
|
||||
|
|
@ -411,40 +421,11 @@ class SearchTestChild(SearchTest):
|
|||
extra_content = models.TextField()
|
||||
|
||||
search_fields = SearchTest.search_fields + [
|
||||
indexed.SearchField('subtitle', partial_match=True),
|
||||
indexed.SearchField('extra_content'),
|
||||
index.SearchField('subtitle', partial_match=True),
|
||||
index.SearchField('extra_content'),
|
||||
]
|
||||
|
||||
|
||||
class SearchTestOldConfig(models.Model, indexed.Indexed):
|
||||
"""
|
||||
This tests that the Indexed class can correctly handle models that
|
||||
use the old "indexed_fields" configuration format.
|
||||
"""
|
||||
indexed_fields = {
|
||||
# A search field with predictive search and boosting
|
||||
'title': {
|
||||
'type': 'string',
|
||||
'analyzer': 'edgengram_analyzer',
|
||||
'boost': 100,
|
||||
},
|
||||
|
||||
# A filter field
|
||||
'live': {
|
||||
'type': 'boolean',
|
||||
'index': 'not_analyzed',
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class SearchTestOldConfigList(models.Model, indexed.Indexed):
|
||||
"""
|
||||
This tests that the Indexed class can correctly handle models that
|
||||
use the old "indexed_fields" configuration format using a list.
|
||||
"""
|
||||
indexed_fields = ['title', 'content']
|
||||
|
||||
|
||||
def routable_page_external_view(request, arg):
|
||||
return HttpResponse("EXTERNAL VIEW: " + arg)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import os
|
||||
|
||||
import django
|
||||
from django.conf import global_settings
|
||||
|
||||
|
||||
|
|
@ -57,7 +58,6 @@ INSTALLED_APPS = [
|
|||
'django.contrib.admin',
|
||||
|
||||
'taggit',
|
||||
'south',
|
||||
'compressor',
|
||||
|
||||
'wagtail.wagtailcore',
|
||||
|
|
@ -68,7 +68,6 @@ INSTALLED_APPS = [
|
|||
'wagtail.wagtailimages',
|
||||
'wagtail.wagtailembeds',
|
||||
'wagtail.wagtailsearch',
|
||||
'wagtail.wagtailredirects',
|
||||
'wagtail.wagtailforms',
|
||||
'wagtail.contrib.wagtailstyleguide',
|
||||
'wagtail.contrib.wagtailsitemaps',
|
||||
|
|
@ -76,6 +75,27 @@ INSTALLED_APPS = [
|
|||
'wagtail.tests',
|
||||
]
|
||||
|
||||
# If we are using Django 1.6, add South to INSTALLED_APPS
|
||||
if django.VERSION < (1, 7):
|
||||
INSTALLED_APPS.append('south')
|
||||
|
||||
|
||||
# If we are using Django 1.7 install wagtailredirects with its appconfig
|
||||
# Theres nothing special about wagtailredirects, we just need to have one
|
||||
# app which uses AppConfigs to test that hooks load properly
|
||||
|
||||
if django.VERSION < (1, 7):
|
||||
INSTALLED_APPS.append('wagtail.wagtailredirects')
|
||||
else:
|
||||
INSTALLED_APPS.append('wagtail.wagtailredirects.apps.WagtailRedirectsAppConfig')
|
||||
|
||||
# As we don't have south migrations for tests, South thinks
|
||||
# the Django 1.7 migrations are South migrations.
|
||||
SOUTH_MIGRATION_MODULES = {
|
||||
'tests': 'ignore',
|
||||
}
|
||||
|
||||
|
||||
# Using DatabaseCache to make sure that the cache is cleared between tests.
|
||||
# This prevents false-positives in some wagtail core tests where we are
|
||||
# changing the 'wagtail_root_paths' key which may cause future tests to fail.
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ from django.http import HttpResponse
|
|||
|
||||
from wagtail.wagtailcore import hooks
|
||||
from wagtail.wagtailcore.whitelist import attribute_rule, check_url, allow_without_attributes
|
||||
from wagtail.wagtailadmin.menu import MenuItem
|
||||
|
||||
|
||||
# Register one hook using decorators...
|
||||
|
|
@ -28,3 +29,12 @@ def block_googlebot(page, request, serve_args, serve_kwargs):
|
|||
if request.META.get('HTTP_USER_AGENT') == 'GoogleBot':
|
||||
return HttpResponse("<h1>bad googlebot no cookie</h1>")
|
||||
hooks.register('before_serve_page', block_googlebot)
|
||||
|
||||
|
||||
class KittensMenuItem(MenuItem):
|
||||
def is_shown(self, request):
|
||||
return not request.GET.get('hide-kittens', False)
|
||||
|
||||
@hooks.register('register_admin_menu_item')
|
||||
def register_kittens_menu_item():
|
||||
return KittensMenuItem('Kittens!', 'http://www.tomroyal.com/teaandkittens/', classnames='icon icon-kitten', attrs={'data-fluffy': 'yes'}, order=10000)
|
||||
|
|
|
|||
35
wagtail/utils/apps.py
Normal file
35
wagtail/utils/apps.py
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
try:
|
||||
from importlib import import_module
|
||||
except ImportError:
|
||||
# for Python 2.6, fall back on django.utils.importlib (deprecated as of Django 1.7)
|
||||
from django.utils.importlib import import_module
|
||||
|
||||
import django
|
||||
from django.conf import settings
|
||||
from django.utils.module_loading import module_has_submodule
|
||||
|
||||
|
||||
def get_app_modules():
|
||||
"""
|
||||
Generator function that yields a module object for each installed app
|
||||
yields tuples of (app_name, module)
|
||||
"""
|
||||
if django.VERSION < (1, 7):
|
||||
# Django 1.6
|
||||
for app in settings.INSTALLED_APPS:
|
||||
yield app, import_module(app)
|
||||
else:
|
||||
# Django 1.7+
|
||||
from django.apps import apps
|
||||
for app in apps.get_app_configs():
|
||||
yield app.name, app.module
|
||||
|
||||
|
||||
def get_app_submodules(submodule_name):
|
||||
"""
|
||||
Searches each app module for the specified submodule
|
||||
yields tuples of (app_name, module)
|
||||
"""
|
||||
for name, module in get_app_modules():
|
||||
if module_has_submodule(module, submodule_name):
|
||||
yield name, import_module('%s.%s' % (name, submodule_name))
|
||||
|
|
@ -1,6 +1,10 @@
|
|||
class RemovedInWagtail06Warning(DeprecationWarning):
|
||||
class RemovedInWagtail07Warning(DeprecationWarning):
|
||||
pass
|
||||
|
||||
|
||||
class RemovedInWagtail07Warning(PendingDeprecationWarning):
|
||||
class RemovedInWagtail08Warning(PendingDeprecationWarning):
|
||||
pass
|
||||
|
||||
|
||||
class RemovedInWagtail08Warning(PendingDeprecationWarning):
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
default_app_config = 'wagtail.wagtailadmin.apps.WagtailAdminAppConfig'
|
||||
7
wagtail/wagtailadmin/apps.py
Normal file
7
wagtail/wagtailadmin/apps.py
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class WagtailAdminAppConfig(AppConfig):
|
||||
name = 'wagtail.wagtailadmin'
|
||||
label = 'wagtailadmin'
|
||||
verbose_name = "Wagtail admin"
|
||||
|
|
@ -491,7 +491,11 @@ class BasePageChooserPanel(BaseChooserPanel):
|
|||
except ValueError:
|
||||
raise ImproperlyConfigured("The page_type passed to PageChooserPanel must be of the form 'app_label.model_name'")
|
||||
|
||||
page_type = get_model(app_label, model_name)
|
||||
try:
|
||||
page_type = get_model(app_label, model_name)
|
||||
except LookupError:
|
||||
page_type = None
|
||||
|
||||
if page_type is None:
|
||||
raise ImproperlyConfigured("PageChooserPanel refers to model '%s' that has not been installed" % cls.page_type)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
# The 'hooks' module is now part of wagtailcore.
|
||||
# Imports are provided here for backwards compatibility
|
||||
|
||||
import warnings
|
||||
|
||||
from wagtail.utils.deprecation import RemovedInWagtail06Warning
|
||||
|
||||
|
||||
warnings.warn(
|
||||
"The wagtail.wagtailadmin.hooks module has been moved. "
|
||||
"Use wagtail.wagtailcore.hooks instead.", RemovedInWagtail06Warning)
|
||||
|
||||
|
||||
from wagtail.wagtailcore.hooks import register, get_hooks
|
||||
BIN
wagtail/wagtailadmin/locale/pt_PT/LC_MESSAGES/django.mo
Normal file
BIN
wagtail/wagtailadmin/locale/pt_PT/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
1127
wagtail/wagtailadmin/locale/pt_PT/LC_MESSAGES/django.po
Normal file
1127
wagtail/wagtailadmin/locale/pt_PT/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,20 +1,56 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from six import text_type
|
||||
from six import text_type, with_metaclass
|
||||
|
||||
try:
|
||||
# renamed util -> utils in Django 1.7; try the new name first
|
||||
from django.forms.utils import flatatt
|
||||
except ImportError:
|
||||
from django.forms.util import flatatt
|
||||
|
||||
from django.conf import settings
|
||||
from django.forms import MediaDefiningClass
|
||||
from django.utils.text import slugify
|
||||
from django.utils.html import format_html
|
||||
from django.utils.html import format_html, format_html_join
|
||||
|
||||
from wagtail.wagtailcore import hooks
|
||||
|
||||
|
||||
class MenuItem(object):
|
||||
def __init__(self, label, url, name=None, classnames='', order=1000):
|
||||
class MenuItem(with_metaclass(MediaDefiningClass)):
|
||||
def __init__(self, label, url, name=None, classnames='', attrs=None, order=1000):
|
||||
self.label = label
|
||||
self.url = url
|
||||
self.classnames = classnames
|
||||
self.name = (name or slugify(text_type(label)))
|
||||
self.order = order
|
||||
|
||||
if attrs:
|
||||
self.attr_string = flatatt(attrs)
|
||||
else:
|
||||
self.attr_string = ""
|
||||
|
||||
def is_shown(self, request):
|
||||
"""
|
||||
Whether this menu item should be shown for the given request; permission
|
||||
checks etc should go here. By default, menu items are shown all the time
|
||||
"""
|
||||
return True
|
||||
|
||||
def render_html(self):
|
||||
return format_html(
|
||||
"""<li class="menu-{0}"><a href="{1}" class="{2}">{3}</a></li>""",
|
||||
self.name, self.url, self.classnames, self.label)
|
||||
"""<li class="menu-{0}"><a href="{1}" class="{2}"{3}>{4}</a></li>""",
|
||||
self.name, self.url, self.classnames, self.attr_string, self.label)
|
||||
|
||||
|
||||
_master_menu_item_list = None
|
||||
def get_master_menu_item_list():
|
||||
"""
|
||||
Return the list of menu items registered with the 'register_admin_menu_item' hook.
|
||||
This is the "master list" because the final admin menu may vary per request
|
||||
according to the value of is_shown() and the construct_main_menu hook.
|
||||
"""
|
||||
global _master_menu_item_list
|
||||
if _master_menu_item_list is None:
|
||||
_master_menu_item_list = [fn() for fn in hooks.get_hooks('register_admin_menu_item')]
|
||||
|
||||
return _master_menu_item_list
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
def create_admin_access_permissions(apps, schema_editor):
|
||||
ContentType = apps.get_model('contenttypes.ContentType')
|
||||
Permission = apps.get_model('auth.Permission')
|
||||
Group = apps.get_model('auth.Group')
|
||||
|
||||
# Add a fake content type to hang the 'can access Wagtail admin' permission off.
|
||||
# The fact that this doesn't correspond to an actual defined model shouldn't matter, I hope...
|
||||
wagtailadmin_content_type = ContentType.objects.create(
|
||||
app_label='wagtailadmin',
|
||||
model='admin',
|
||||
name='Wagtail admin'
|
||||
)
|
||||
|
||||
# Create admin permission
|
||||
admin_permission = Permission.objects.create(
|
||||
content_type=wagtailadmin_content_type,
|
||||
codename='access_admin',
|
||||
name='Can access Wagtail admin'
|
||||
)
|
||||
|
||||
# Assign it to Editors and Moderators groups
|
||||
for group in Group.objects.filter(name__in=['Editors', 'Moderators']):
|
||||
group.permissions.add(admin_permission)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
# Need to run wagtailcores initial data migration to make sure the groups are created
|
||||
('wagtailcore', '0002_initial_data'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(create_admin_access_permissions),
|
||||
]
|
||||
0
wagtail/wagtailadmin/migrations/__init__.py
Normal file
0
wagtail/wagtailadmin/migrations/__init__.py
Normal file
|
|
@ -21,32 +21,6 @@ $(function(){
|
|||
}
|
||||
});
|
||||
|
||||
// Dynamically load menu on request.
|
||||
$(document).on('click', '.dl-trigger', function(){
|
||||
var $this = $(this);
|
||||
var $explorer = $('#explorer');
|
||||
|
||||
$this.addClass('icon-spinner');
|
||||
|
||||
if(!$explorer.children().length){
|
||||
$explorer.load(window.explorer_menu_url, function() {
|
||||
$this.removeClass('icon-spinner');
|
||||
|
||||
$explorer.addClass('dl-menuwrapper').dlmenu({
|
||||
animationClasses : {
|
||||
classin : 'dl-animate-in-2',
|
||||
classout : 'dl-animate-out-2'
|
||||
}
|
||||
});
|
||||
$explorer.dlmenu('openMenu');
|
||||
});
|
||||
}else{
|
||||
$explorer.dlmenu('openMenu');
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
// Resize nav to fit height of window. This is an unimportant bell/whistle to make it look nice
|
||||
var fitNav = function(){
|
||||
$('.nav-wrapper').css('min-height',$(window).height());
|
||||
|
|
|
|||
27
wagtail/wagtailadmin/static/wagtailadmin/js/explorer-menu.js
Normal file
27
wagtail/wagtailadmin/static/wagtailadmin/js/explorer-menu.js
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
$(function(){
|
||||
// Dynamically load menu on request.
|
||||
$(document).on('click', '.dl-trigger', function(){
|
||||
var $this = $(this);
|
||||
var $explorer = $('#explorer');
|
||||
|
||||
$this.addClass('icon-spinner');
|
||||
|
||||
if(!$explorer.children().length){
|
||||
$explorer.load($this.data('explorer-menu-url'), function() {
|
||||
$this.removeClass('icon-spinner');
|
||||
|
||||
$explorer.addClass('dl-menuwrapper').dlmenu({
|
||||
animationClasses : {
|
||||
classin : 'dl-animate-in-2',
|
||||
classout : 'dl-animate-out-2'
|
||||
}
|
||||
});
|
||||
$explorer.dlmenu('openMenu');
|
||||
});
|
||||
}else{
|
||||
$explorer.dlmenu('openMenu');
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
});
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -56,7 +56,6 @@ kbd{
|
|||
/* Help text formatters */
|
||||
|
||||
.help-block{
|
||||
float:left;
|
||||
padding:1em;
|
||||
margin:1em 0;
|
||||
clear:both;
|
||||
|
|
|
|||
|
|
@ -4,19 +4,19 @@ from django.contrib.contenttypes.models import ContentType
|
|||
from django.db.models import Count
|
||||
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
||||
|
||||
from wagtail.wagtailsearch import indexed
|
||||
from wagtail.wagtailsearch import index
|
||||
from wagtail.wagtailsearch.backends import get_search_backend
|
||||
|
||||
|
||||
class TagSearchable(indexed.Indexed):
|
||||
class TagSearchable(index.Indexed):
|
||||
"""
|
||||
Mixin to provide a 'search' method, searching on the 'title' field and tags,
|
||||
for models that provide those things.
|
||||
"""
|
||||
|
||||
search_fields = (
|
||||
indexed.SearchField('title', partial_match=True, boost=10),
|
||||
indexed.SearchField('get_tags', partial_match=True, boost=10)
|
||||
index.SearchField('title', partial_match=True, boost=10),
|
||||
index.SearchField('get_tags', partial_match=True, boost=10)
|
||||
)
|
||||
|
||||
@property
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{% extends "wagtailadmin/skeleton.html" %}
|
||||
{% load compress %}
|
||||
{% load compress wagtailadmin_tags %}
|
||||
|
||||
{% block css %}
|
||||
{% compress css %}
|
||||
|
|
@ -22,9 +22,7 @@
|
|||
<script src="{{ STATIC_URL }}wagtailadmin/js/vendor/bootstrap-tab.js"></script>
|
||||
<script src="{{ STATIC_URL }}wagtailadmin/js/vendor/jquery.dlmenu.js"></script>
|
||||
<script src="{{ STATIC_URL }}wagtailadmin/js/core.js"></script>
|
||||
<script>
|
||||
window.explorer_menu_url = "{% url 'wagtailadmin_explorer_nav' %}";
|
||||
</script>
|
||||
{% main_nav_js %}
|
||||
{% endcompress %}
|
||||
|
||||
{% block extra_js %}{% endblock %}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,19 @@
|
|||
{% load i18n %}
|
||||
|
||||
{% if page_types_restricted %}
|
||||
<p class="help-block help-warning">
|
||||
{% blocktrans with type=page_type.get_verbose_name %}
|
||||
Only pages of type "{{ type }}" may be chosen for this field. Search results will exclude pages of other types.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{% if not is_searching %}
|
||||
<h2>{% trans "Explorer" %}</h2>
|
||||
{% include "wagtailadmin/shared/breadcrumb.html" with page=parent_page choosing=1 %}
|
||||
|
||||
{% else %}
|
||||
<h2>
|
||||
{% blocktrans count counter=pages.count %}
|
||||
{% blocktrans count counter=pages|length %}
|
||||
There is one match
|
||||
{% plural %}
|
||||
There are {{ counter }} matches
|
||||
|
|
@ -13,8 +21,10 @@
|
|||
</h2>
|
||||
{% endif %}
|
||||
|
||||
{% if is_searching %}
|
||||
{% include "wagtailadmin/pages/list.html" with choosing=1 show_parent=1 pages=pages parent_page=parent_page %}
|
||||
{% else %}
|
||||
{% include "wagtailadmin/pages/list.html" with choosing=1 allow_navigation=1 orderable=0 pages=pages parent_page=parent_page %}
|
||||
{% if pages %}
|
||||
{% if is_searching %}
|
||||
{% include "wagtailadmin/pages/list.html" with choosing=1 show_parent=1 pages=pages parent_page=parent_page %}
|
||||
{% else %}
|
||||
{% include "wagtailadmin/pages/list.html" with choosing=1 allow_navigation=1 orderable=0 pages=pages parent_page=parent_page %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
|
@ -1,13 +1,17 @@
|
|||
{% load i18n %}
|
||||
{% trans "Choose a page" as choose_str %}
|
||||
{% include "wagtailadmin/shared/header.html" with title=choose_str search_url="wagtailadmin_choose_page" icon="doc-empty-inverse" %}
|
||||
{% if page_types_restricted %}
|
||||
{% trans "Choose" as choose_str %}
|
||||
{% trans page_type.get_verbose_name as subtitle %}
|
||||
{% else %}
|
||||
{% trans "Choose a page" as choose_str %}
|
||||
{% endif %}
|
||||
|
||||
{% include "wagtailadmin/shared/header.html" with title=choose_str subtitle=subtitle search_url="wagtailadmin_choose_page" query_parameters="page_type="|add:page_type_string icon="doc-empty-inverse" %}
|
||||
|
||||
<div class="nice-padding">
|
||||
{% include 'wagtailadmin/chooser/_link_types.html' with current='internal' %}
|
||||
|
||||
<div class="page-results">
|
||||
{# content in here will be replaced by live search results #}
|
||||
|
||||
{% include 'wagtailadmin/chooser/_search_results.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
{% include "wagtailadmin/shared/header.html" with title=title_str icon="locked" %}
|
||||
|
||||
<div class="nice-padding">
|
||||
<p>{% trans "<b>Note:</b> privacy changes apply to all children of this page too." %}</p>
|
||||
<p class="help-block help-warning">{% trans "Privacy changes apply to all children of this page too." %}</p>
|
||||
<form action="{% url 'wagtailadmin_pages_set_privacy' page.id %}" method="POST">
|
||||
{% csrf_token %}
|
||||
<ul class="fields">
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<h1 class="icon icon-{{ icon }}">{{ title }} <span>{{ subtitle }}</span></h1>
|
||||
</div>
|
||||
{% if search_url %}
|
||||
<form class="col search-form" action="{% url search_url %}" method="get">
|
||||
<form class="col search-form" action="{% url search_url %}{% if query_parameters %}?{{ query_parameters }}{% endif %}" method="get">
|
||||
<ul class="fields">
|
||||
{% for field in search_form %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=field field_classes="field-small iconfield" input_classes="icon-search" %}
|
||||
|
|
|
|||
|
|
@ -2,14 +2,12 @@ from __future__ import unicode_literals
|
|||
|
||||
from django.conf import settings
|
||||
from django import template
|
||||
from django.core import urlresolvers
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from wagtail.wagtailadmin.menu import MenuItem
|
||||
from django.forms import Media
|
||||
|
||||
from wagtail.wagtailcore import hooks
|
||||
from wagtail.wagtailcore.models import get_navigation_menu_items, UserPagePermissionsProxy, PageViewRestriction
|
||||
from wagtail.wagtailcore.utils import camelcase_to_underscore
|
||||
from wagtail.wagtailadmin.menu import get_master_menu_item_list
|
||||
|
||||
|
||||
register = template.Library()
|
||||
|
|
@ -31,12 +29,8 @@ def explorer_subnav(nodes):
|
|||
|
||||
@register.inclusion_tag('wagtailadmin/shared/main_nav.html', takes_context=True)
|
||||
def main_nav(context):
|
||||
menu_items = [
|
||||
MenuItem(_('Explorer'), urlresolvers.reverse('wagtailadmin_explore_root'), classnames='icon icon-folder-open-inverse dl-trigger', order=100),
|
||||
MenuItem(_('Search'), urlresolvers.reverse('wagtailadmin_pages_search'), classnames='icon icon-search', order=200),
|
||||
]
|
||||
|
||||
request = context['request']
|
||||
menu_items = [item for item in get_master_menu_item_list() if item.is_shown(request)]
|
||||
|
||||
for fn in hooks.get_hooks('construct_main_menu'):
|
||||
fn(request, menu_items)
|
||||
|
|
@ -46,6 +40,14 @@ def main_nav(context):
|
|||
'request': request,
|
||||
}
|
||||
|
||||
@register.simple_tag
|
||||
def main_nav_js():
|
||||
media = Media()
|
||||
for item in get_master_menu_item_list():
|
||||
media += item.media
|
||||
|
||||
return media['js']
|
||||
|
||||
|
||||
@register.filter("ellipsistrim")
|
||||
def ellipsistrim(value, max_length):
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@ import warnings
|
|||
from django import template
|
||||
from django.template.loader import render_to_string
|
||||
|
||||
from wagtail.utils.deprecation import RemovedInWagtail06Warning
|
||||
|
||||
from wagtail.wagtailcore.models import Page
|
||||
|
||||
|
||||
|
|
@ -12,13 +10,7 @@ register = template.Library()
|
|||
|
||||
|
||||
@register.simple_tag(takes_context=True)
|
||||
def wagtailuserbar(context, css_path=None):
|
||||
if css_path is not None:
|
||||
warnings.warn(
|
||||
"Passing a CSS path to the wagtailuserbar tag is no longer required; use {% wagtailuserbar %} instead",
|
||||
RemovedInWagtail06Warning
|
||||
)
|
||||
|
||||
def wagtailuserbar(context):
|
||||
# Find request object
|
||||
request = context['request']
|
||||
|
||||
|
|
|
|||
|
|
@ -43,9 +43,6 @@ class TestGetFormForModel(TestCase):
|
|||
|
||||
|
||||
class TestExtractPanelDefinitionsFromModelClass(TestCase):
|
||||
class FakePage(Page):
|
||||
pass
|
||||
|
||||
def test_can_extract_panels(self):
|
||||
mock = MagicMock()
|
||||
mock.panels = 'foo'
|
||||
|
|
@ -58,7 +55,7 @@ class TestExtractPanelDefinitionsFromModelClass(TestCase):
|
|||
self.assertNotEqual(panel.field_name, 'hostname')
|
||||
|
||||
def test_extracted_objects_are_panels(self):
|
||||
panels = extract_panel_definitions_from_model_class(self.FakePage)
|
||||
panels = extract_panel_definitions_from_model_class(Page)
|
||||
for panel in panels:
|
||||
self.assertTrue(issubclass(panel, BaseFieldPanel))
|
||||
|
||||
|
|
@ -346,11 +343,27 @@ class TestInlinePanel(TestCase):
|
|||
fake_page = self.FakePage()
|
||||
self.barbecue = fake_page
|
||||
|
||||
class FakePanel(object):
|
||||
name = 'mock panel'
|
||||
|
||||
class FakeChild(object):
|
||||
def render_js(self):
|
||||
return "rendered js"
|
||||
|
||||
def rendered_fields(self):
|
||||
return ["rendered fields"]
|
||||
|
||||
def init(*args, **kwargs):
|
||||
pass
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
fake_child = self.FakeChild()
|
||||
return fake_child
|
||||
|
||||
def setUp(self):
|
||||
self.fake_field = self.FakeField()
|
||||
self.fake_instance = self.FakeInstance()
|
||||
self.mock_panel = MagicMock()
|
||||
self.mock_panel.name = 'mock panel'
|
||||
self.mock_panel = self.FakePanel()
|
||||
self.mock_model = MagicMock()
|
||||
self.mock_model.formset.related.model.panels = [self.mock_panel]
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ from django.core import mail
|
|||
from django.core.paginator import Paginator
|
||||
from django.utils import timezone
|
||||
|
||||
from wagtail.tests.models import SimplePage, EventPage, EventPageCarouselItem, StandardIndex, BusinessIndex, BusinessChild, BusinessSubIndex, TaggedPage
|
||||
from wagtail.tests.models import SimplePage, EventPage, EventPageCarouselItem, StandardIndex, BusinessIndex, BusinessChild, BusinessSubIndex, TaggedPage, Advert, AdvertPlacement
|
||||
from wagtail.tests.utils import unittest, WagtailTestUtils
|
||||
from wagtail.wagtailcore.models import Page, PageRevision
|
||||
from wagtail.wagtailcore.signals import page_published, page_unpublished
|
||||
|
|
@ -1699,3 +1699,91 @@ class TestIssue197(TestCase, WagtailTestUtils):
|
|||
page = TaggedPage.objects.get(id=self.tagged_page.id)
|
||||
self.assertIn('hello', page.tags.slugs())
|
||||
self.assertIn('world', page.tags.slugs())
|
||||
|
||||
|
||||
class TestChildRelationsOnSuperclass(TestCase, WagtailTestUtils):
|
||||
# In our test models we define AdvertPlacement as a child relation on the Page model.
|
||||
# Here we check that this behaves correctly when exposed on the edit form of a Page
|
||||
# subclass (StandardIndex here).
|
||||
fixtures = ['test.json']
|
||||
|
||||
def setUp(self):
|
||||
# Find root page
|
||||
self.root_page = Page.objects.get(id=2)
|
||||
self.test_advert = Advert.objects.get(id=1)
|
||||
|
||||
# Add child page
|
||||
self.index_page = StandardIndex(
|
||||
title="My lovely index",
|
||||
slug="my-lovely-index",
|
||||
advert_placements=[AdvertPlacement(advert=self.test_advert)]
|
||||
)
|
||||
self.root_page.add_child(instance=self.index_page)
|
||||
|
||||
# Login
|
||||
self.login()
|
||||
|
||||
def test_get_create_form(self):
|
||||
response = self.client.get(reverse('wagtailadmin_pages_create', args=('tests', 'standardindex', self.root_page.id)))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
# Response should include an advert_placements formset labelled Adverts
|
||||
self.assertContains(response, "Adverts")
|
||||
self.assertContains(response, "id_advert_placements-TOTAL_FORMS")
|
||||
|
||||
def test_post_create_form(self):
|
||||
post_data = {
|
||||
'title': "New index!",
|
||||
'slug': 'new-index',
|
||||
'advert_placements-TOTAL_FORMS': '1',
|
||||
'advert_placements-INITIAL_FORMS': '0',
|
||||
'advert_placements-MAX_NUM_FORMS': '1000',
|
||||
'advert_placements-0-advert': '1',
|
||||
'advert_placements-0-colour': 'yellow',
|
||||
'advert_placements-0-id': '',
|
||||
}
|
||||
response = self.client.post(reverse('wagtailadmin_pages_create', args=('tests', 'standardindex', self.root_page.id)), post_data)
|
||||
|
||||
# Should be redirected to explorer page
|
||||
self.assertRedirects(response, reverse('wagtailadmin_explore', args=(self.root_page.id, )))
|
||||
|
||||
# Find the page and check it
|
||||
page = Page.objects.get(path__startswith=self.root_page.path, slug='new-index').specific
|
||||
self.assertEqual(page.advert_placements.count(), 1)
|
||||
self.assertEqual(page.advert_placements.first().advert.text, 'test_advert')
|
||||
|
||||
def test_get_edit_form(self):
|
||||
response = self.client.get(reverse('wagtailadmin_pages_edit', args=(self.index_page.id, )))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
# Response should include an advert_placements formset labelled Adverts
|
||||
self.assertContains(response, "Adverts")
|
||||
self.assertContains(response, "id_advert_placements-TOTAL_FORMS")
|
||||
# the formset should be populated with an existing form
|
||||
self.assertContains(response, "id_advert_placements-0-advert")
|
||||
self.assertContains(response, '<option value="1" selected="selected">test_advert</option>')
|
||||
|
||||
def test_post_edit_form(self):
|
||||
post_data = {
|
||||
'title': "My lovely index",
|
||||
'slug': 'my-lovely-index',
|
||||
'advert_placements-TOTAL_FORMS': '2',
|
||||
'advert_placements-INITIAL_FORMS': '1',
|
||||
'advert_placements-MAX_NUM_FORMS': '1000',
|
||||
'advert_placements-0-advert': '1',
|
||||
'advert_placements-0-colour': 'yellow',
|
||||
'advert_placements-0-id': self.index_page.advert_placements.first().id,
|
||||
'advert_placements-1-advert': '1',
|
||||
'advert_placements-1-colour': 'purple',
|
||||
'advert_placements-1-id': '',
|
||||
'action-publish': "Publish",
|
||||
}
|
||||
response = self.client.post(reverse('wagtailadmin_pages_edit', args=(self.index_page.id, )), post_data)
|
||||
|
||||
# Should be redirected to explorer page
|
||||
self.assertRedirects(response, reverse('wagtailadmin_explore', args=(self.root_page.id, )))
|
||||
|
||||
# Find the page and check it
|
||||
page = Page.objects.get(id=self.index_page.id).specific
|
||||
self.assertEqual(page.advert_placements.count(), 2)
|
||||
self.assertEqual(page.advert_placements.all()[0].advert.text, 'test_advert')
|
||||
self.assertEqual(page.advert_placements.all()[1].advert.text, 'test_advert')
|
||||
|
|
|
|||
|
|
@ -16,6 +16,18 @@ class TestHome(TestCase, WagtailTestUtils):
|
|||
response = self.client.get(reverse('wagtailadmin_home'))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_admin_menu(self):
|
||||
response = self.client.get(reverse('wagtailadmin_home'))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
# check that media attached to menu items is correctly pulled in
|
||||
self.assertContains(response, '<script type="text/javascript" src="/static/wagtailadmin/js/explorer-menu.js"></script>')
|
||||
# check that custom menu items (including classname / attrs parameters) are pulled in
|
||||
self.assertContains(response, '<a href="http://www.tomroyal.com/teaandkittens/" class="icon icon-kitten" data-fluffy="yes">Kittens!</a>')
|
||||
|
||||
# check that is_shown is respected on menu items
|
||||
response = self.client.get(reverse('wagtailadmin_home') + '?hide-kittens=true')
|
||||
self.assertNotContains(response, '<a href="http://www.tomroyal.com/teaandkittens/" class="icon icon-kitten" data-fluffy="yes">Kittens!</a>')
|
||||
|
||||
|
||||
class TestEditorHooks(TestCase, WagtailTestUtils):
|
||||
def setUp(self):
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ from django.shortcuts import get_object_or_404, render
|
|||
from django.http import Http404
|
||||
from django.utils.http import urlencode
|
||||
from django.contrib.auth.decorators import permission_required
|
||||
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
||||
|
||||
from wagtail.wagtailadmin.modal_workflow import render_modal_workflow
|
||||
from wagtail.wagtailadmin.forms import SearchForm, ExternalLinkChooserForm, ExternalLinkChooserWithLinkTextForm, EmailLinkChooserForm, EmailLinkChooserWithLinkTextForm
|
||||
|
|
@ -25,6 +26,7 @@ def browse(request, parent_page_id=None):
|
|||
content_type_app_name, content_type_model_name = page_type.split('.')
|
||||
|
||||
is_searching = False
|
||||
page_types_restricted = page_type != 'wagtailcore.page'
|
||||
|
||||
try:
|
||||
content_type = ContentType.objects.get_by_natural_key(content_type_app_name, content_type_model_name)
|
||||
|
|
@ -66,8 +68,11 @@ def browse(request, parent_page_id=None):
|
|||
return render(request, 'wagtailadmin/chooser/_search_results.html', {
|
||||
'querystring': get_querystring(request),
|
||||
'searchform': search_form,
|
||||
'pages': pages,
|
||||
'is_searching': is_searching
|
||||
'pages': shown_pages,
|
||||
'is_searching': is_searching,
|
||||
'page_type_string': page_type,
|
||||
'page_type': desired_class,
|
||||
'page_types_restricted': page_types_restricted
|
||||
})
|
||||
|
||||
return render_modal_workflow(request, 'wagtailadmin/chooser/browse.html', 'wagtailadmin/chooser/browse.js', {
|
||||
|
|
@ -77,7 +82,10 @@ def browse(request, parent_page_id=None):
|
|||
'parent_page': parent_page,
|
||||
'pages': shown_pages,
|
||||
'search_form': search_form,
|
||||
'is_searching': False
|
||||
'is_searching': False,
|
||||
'page_type_string': page_type,
|
||||
'page_type': desired_class,
|
||||
'page_types_restricted': page_types_restricted
|
||||
})
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@ from django.utils.translation import ugettext as _
|
|||
from django.views.decorators.http import require_GET
|
||||
from django.views.decorators.vary import vary_on_headers
|
||||
|
||||
from wagtail.utils.deprecation import RemovedInWagtail06Warning
|
||||
|
||||
from wagtail.wagtailadmin.edit_handlers import TabbedInterface, ObjectList
|
||||
from wagtail.wagtailadmin.forms import SearchForm, CopyForm
|
||||
from wagtail.wagtailadmin import tasks, signals
|
||||
|
|
@ -427,27 +425,6 @@ def view_draft(request, page_id):
|
|||
return page.serve_preview(page.dummy_request(), page.default_preview_mode)
|
||||
|
||||
|
||||
def get_preview_response(page, preview_mode):
|
||||
"""
|
||||
Helper function for preview_on_edit and preview_on_create -
|
||||
return a page's preview response via either serve_preview or the deprecated
|
||||
show_as_mode method
|
||||
"""
|
||||
# Check the deprecated Page.show_as_mode method, as subclasses of Page
|
||||
# might be overriding that to return a response
|
||||
response = page.show_as_mode(preview_mode)
|
||||
if response:
|
||||
warnings.warn(
|
||||
"Defining 'show_as_mode' on a page model is deprecated. Use 'serve_preview' instead",
|
||||
RemovedInWagtail06Warning
|
||||
)
|
||||
return response
|
||||
else:
|
||||
# show_as_mode did not return a response, so go ahead and use the 'proper'
|
||||
# serve_preview method
|
||||
return page.serve_preview(page.dummy_request(), preview_mode)
|
||||
|
||||
|
||||
@permission_required('wagtailadmin.access_admin')
|
||||
def preview_on_edit(request, page_id):
|
||||
# Receive the form submission that would typically be posted to the 'edit' view. If submission is valid,
|
||||
|
|
@ -462,8 +439,7 @@ def preview_on_edit(request, page_id):
|
|||
form.save(commit=False)
|
||||
|
||||
preview_mode = request.GET.get('mode', page.default_preview_mode)
|
||||
response = get_preview_response(page, preview_mode)
|
||||
|
||||
response = page.serve_preview(page.dummy_request(), preview_mode)
|
||||
response['X-Wagtail-Preview'] = 'ok'
|
||||
return response
|
||||
|
||||
|
|
@ -507,8 +483,7 @@ def preview_on_create(request, content_type_app_name, content_type_model_name, p
|
|||
page.path = Page._get_children_path_interval(parent_page.path)[1]
|
||||
|
||||
preview_mode = request.GET.get('mode', page.default_preview_mode)
|
||||
response = get_preview_response(page, preview_mode)
|
||||
|
||||
response = page.serve_preview(page.dummy_request(), preview_mode)
|
||||
response['X-Wagtail-Preview'] = 'ok'
|
||||
return response
|
||||
|
||||
|
|
|
|||
24
wagtail/wagtailadmin/wagtail_hooks.py
Normal file
24
wagtail/wagtailadmin/wagtail_hooks.py
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
from django.core import urlresolvers
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from wagtail.wagtailcore import hooks
|
||||
from wagtail.wagtailadmin.menu import MenuItem
|
||||
|
||||
|
||||
class ExplorerMenuItem(MenuItem):
|
||||
class Media:
|
||||
js = ['wagtailadmin/js/explorer-menu.js']
|
||||
|
||||
@hooks.register('register_admin_menu_item')
|
||||
def register_explorer_menu_item():
|
||||
return ExplorerMenuItem(
|
||||
_('Explorer'), urlresolvers.reverse('wagtailadmin_explore_root'),
|
||||
classnames='icon icon-folder-open-inverse dl-trigger',
|
||||
attrs={'data-explorer-menu-url': urlresolvers.reverse('wagtailadmin_explorer_nav')},
|
||||
order=100)
|
||||
|
||||
@hooks.register('register_admin_menu_item')
|
||||
def register_search_menu_item():
|
||||
return MenuItem(
|
||||
_('Search'), urlresolvers.reverse('wagtailadmin_pages_search'),
|
||||
classnames='icon icon-search', order=200)
|
||||
|
|
@ -0,0 +1 @@
|
|||
default_app_config = 'wagtail.wagtailcore.apps.WagtailCoreAppConfig'
|
||||
7
wagtail/wagtailcore/apps.py
Normal file
7
wagtail/wagtailcore/apps.py
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class WagtailCoreAppConfig(AppConfig):
|
||||
name = 'wagtail.wagtailcore'
|
||||
label = 'wagtailcore'
|
||||
verbose_name = "Wagtail core"
|
||||
|
|
@ -1,9 +1,5 @@
|
|||
from django.conf import settings
|
||||
try:
|
||||
from importlib import import_module
|
||||
except ImportError:
|
||||
# for Python 2.6, fall back on django.utils.importlib (deprecated as of Django 1.7)
|
||||
from django.utils.importlib import import_module
|
||||
from wagtail.utils.apps import get_app_submodules
|
||||
|
||||
|
||||
_hooks = {}
|
||||
|
||||
|
|
@ -40,12 +36,7 @@ _searched_for_hooks = False
|
|||
def search_for_hooks():
|
||||
global _searched_for_hooks
|
||||
if not _searched_for_hooks:
|
||||
for app_module in settings.INSTALLED_APPS:
|
||||
try:
|
||||
import_module('%s.wagtail_hooks' % app_module)
|
||||
except ImportError:
|
||||
continue
|
||||
|
||||
list(get_app_submodules('wagtail_hooks'))
|
||||
_searched_for_hooks = True
|
||||
|
||||
|
||||
|
|
|
|||
BIN
wagtail/wagtailcore/locale/pt_PT/LC_MESSAGES/django.mo
Normal file
BIN
wagtail/wagtailcore/locale/pt_PT/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
97
wagtail/wagtailcore/locale/pt_PT/LC_MESSAGES/django.po
Normal file
97
wagtail/wagtailcore/locale/pt_PT/LC_MESSAGES/django.po
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
# Translators:
|
||||
# Thiago Cangussu <cangussu.thg@gmail.com>, 2014
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Wagtail 0.5.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2014-08-01 16:38+0100\n"
|
||||
"PO-Revision-Date: 2014-08-03 01:52+0100\n"
|
||||
"Last-Translator: Jose Lourenco <jose@lourenco.ws>\n"
|
||||
"Language-Team: \n"
|
||||
"Language: pt_PT\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: pt_PT\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
"X-Generator: Poedit 1.5.4\n"
|
||||
|
||||
#: models.py:46
|
||||
msgid ""
|
||||
"Set this to something other than 80 if you need a specific port number to "
|
||||
"appear in URLs (e.g. development on port 8000). Does not affect request "
|
||||
"handling (so port forwarding still works)."
|
||||
msgstr ""
|
||||
"Atribua um valor diferente de 80 se você necessitar que um número de porto "
|
||||
"específico apareça nas URLs (ex. desenvolvimento no porto 8000). Não afeta o "
|
||||
"tratamento de requisições (assim, o redirecionamento de portos continua a "
|
||||
"funcionar)."
|
||||
|
||||
#: models.py:48
|
||||
msgid ""
|
||||
"If true, this site will handle requests for all other hostnames that do not "
|
||||
"have a site entry of their own"
|
||||
msgstr ""
|
||||
"Se verdadeiro, este site irá processar requisições de todos os outros "
|
||||
"hostnames que não tenham um site próprio"
|
||||
|
||||
#: models.py:109
|
||||
#, python-format
|
||||
msgid ""
|
||||
"%(hostname)s is already configured as the default site. You must unset that "
|
||||
"before you can save this site as default."
|
||||
msgstr ""
|
||||
"O %(hostname)s já está configurado como site pré-definido. Tem de alterar "
|
||||
"essa configuração antes de poder guardar este site como pré-definido."
|
||||
|
||||
#: models.py:277
|
||||
msgid "The page title as you'd like it to be seen by the public"
|
||||
msgstr "O título da página como você gostaria que fosse visto pelo público"
|
||||
|
||||
#: models.py:278
|
||||
msgid ""
|
||||
"The name of the page as it will appear in URLs e.g http://domain.com/blog/"
|
||||
"[my-slug]/"
|
||||
msgstr ""
|
||||
"O nome da página como ele irá aparecer nas URLs ex.: http://domain.com/blog/"
|
||||
"[my-slug]/"
|
||||
|
||||
#: models.py:287
|
||||
msgid "Page title"
|
||||
msgstr "Título da página"
|
||||
|
||||
#: models.py:287
|
||||
msgid ""
|
||||
"Optional. 'Search Engine Friendly' title. This will appear at the top of the "
|
||||
"browser window."
|
||||
msgstr ""
|
||||
"Opcional. Título 'Amigável para Motores de Busca'. Isto irá aparecer no topo "
|
||||
"da janela do navegador."
|
||||
|
||||
#: models.py:288
|
||||
msgid ""
|
||||
"Whether a link to this page will appear in automatically generated menus"
|
||||
msgstr ""
|
||||
"Se um link para esta página irá aparecer nos menus gerados automaticamente"
|
||||
|
||||
#: models.py:291
|
||||
msgid "Go live date/time"
|
||||
msgstr "Data/hora de publicação"
|
||||
|
||||
#: models.py:291 models.py:292
|
||||
msgid "Please add a date-time in the form YYYY-MM-DD hh:mm:ss."
|
||||
msgstr "Por favor adicione uma data-hora no formato AAAA-MM-DD hh:mm:ss."
|
||||
|
||||
#: models.py:292
|
||||
msgid "Expiry date/time"
|
||||
msgstr "Data/hora terminal"
|
||||
|
||||
#: models.py:564
|
||||
msgid "name '{0}' (used in subpage_types list) is not defined."
|
||||
msgstr ""
|
||||
"O nome '{0}' (usado na lista de tipos de sub-páginas) não está definido."
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
from django.core.management.base import BaseCommand
|
||||
from django.db import models
|
||||
|
||||
from modelcluster.models import get_all_child_relations
|
||||
|
||||
from wagtail.wagtailcore.models import PageRevision, get_page_types
|
||||
|
||||
|
||||
|
|
@ -27,10 +29,7 @@ class Command(BaseCommand):
|
|||
self.stdout.write("scanning %s" % content_type.name)
|
||||
page_class = content_type.model_class()
|
||||
|
||||
try:
|
||||
child_relation_names = [rel.get_accessor_name() for rel in page_class._meta.child_relations]
|
||||
except AttributeError:
|
||||
child_relation_names = []
|
||||
child_relation_names = [rel.get_accessor_name() for rel in get_all_child_relations(page_class)]
|
||||
|
||||
for page in page_class.objects.all():
|
||||
replace_in_model(page, from_text, to_text)
|
||||
|
|
|
|||
104
wagtail/wagtailcore/migrations/0001_initial.py
Normal file
104
wagtail/wagtailcore/migrations/0001_initial.py
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.conf import settings
|
||||
import wagtail.wagtailsearch.index
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('auth', '0001_initial'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('contenttypes', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='GroupPagePermission',
|
||||
fields=[
|
||||
('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('permission_type', models.CharField(choices=[('add', 'Add'), ('edit', 'Edit'), ('publish', 'Publish')], max_length=20)),
|
||||
('group', models.ForeignKey(to='auth.Group', related_name='page_permissions')),
|
||||
],
|
||||
options={
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Page',
|
||||
fields=[
|
||||
('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('path', models.CharField(max_length=255, unique=True)),
|
||||
('depth', models.PositiveIntegerField()),
|
||||
('numchild', models.PositiveIntegerField(default=0)),
|
||||
('title', models.CharField(max_length=255, help_text="The page title as you'd like it to be seen by the public")),
|
||||
('slug', models.SlugField(help_text='The name of the page as it will appear in URLs e.g http://domain.com/blog/[my-slug]/')),
|
||||
('live', models.BooleanField(default=True, editable=False)),
|
||||
('has_unpublished_changes', models.BooleanField(default=False, editable=False)),
|
||||
('url_path', models.CharField(blank=True, max_length=255, editable=False)),
|
||||
('seo_title', models.CharField(blank=True, max_length=255, help_text="Optional. 'Search Engine Friendly' title. This will appear at the top of the browser window.", verbose_name='Page title')),
|
||||
('show_in_menus', models.BooleanField(default=False, help_text='Whether a link to this page will appear in automatically generated menus')),
|
||||
('search_description', models.TextField(blank=True)),
|
||||
('go_live_at', models.DateTimeField(blank=True, verbose_name='Go live date/time', null=True, help_text='Please add a date-time in the form YYYY-MM-DD hh:mm:ss.')),
|
||||
('expire_at', models.DateTimeField(blank=True, verbose_name='Expiry date/time', null=True, help_text='Please add a date-time in the form YYYY-MM-DD hh:mm:ss.')),
|
||||
('expired', models.BooleanField(default=False, editable=False)),
|
||||
('content_type', models.ForeignKey(to='contenttypes.ContentType', related_name='pages')),
|
||||
('owner', models.ForeignKey(blank=True, null=True, to=settings.AUTH_USER_MODEL, editable=False, related_name='owned_pages')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
bases=(models.Model, wagtail.wagtailsearch.index.Indexed),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='PageRevision',
|
||||
fields=[
|
||||
('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('submitted_for_moderation', models.BooleanField(default=False)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('content_json', models.TextField()),
|
||||
('approved_go_live_at', models.DateTimeField(blank=True, null=True)),
|
||||
('page', models.ForeignKey(to='wagtailcore.Page', related_name='revisions')),
|
||||
('user', models.ForeignKey(blank=True, null=True, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='PageViewRestriction',
|
||||
fields=[
|
||||
('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('password', models.CharField(max_length=255)),
|
||||
('page', models.ForeignKey(to='wagtailcore.Page', related_name='view_restrictions')),
|
||||
],
|
||||
options={
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Site',
|
||||
fields=[
|
||||
('id', models.AutoField(serialize=False, verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('hostname', models.CharField(max_length=255, db_index=True)),
|
||||
('port', models.IntegerField(default=80, help_text='Set this to something other than 80 if you need a specific port number to appear in URLs (e.g. development on port 8000). Does not affect request handling (so port forwarding still works).')),
|
||||
('is_default_site', models.BooleanField(default=False, help_text='If true, this site will handle requests for all other hostnames that do not have a site entry of their own')),
|
||||
('root_page', models.ForeignKey(to='wagtailcore.Page', related_name='sites_rooted_here')),
|
||||
],
|
||||
options={
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='site',
|
||||
unique_together=set([('hostname', 'port')]),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='grouppagepermission',
|
||||
name='page',
|
||||
field=models.ForeignKey(to='wagtailcore.Page', related_name='group_permissions'),
|
||||
preserve_default=True,
|
||||
),
|
||||
]
|
||||
91
wagtail/wagtailcore/migrations/0002_initial_data.py
Normal file
91
wagtail/wagtailcore/migrations/0002_initial_data.py
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
def initial_data(apps, schema_editor):
|
||||
ContentType = apps.get_model('contenttypes.ContentType')
|
||||
Group = apps.get_model('auth.Group')
|
||||
Page = apps.get_model('wagtailcore.Page')
|
||||
Site = apps.get_model('wagtailcore.Site')
|
||||
GroupPagePermission = apps.get_model('wagtailcore.GroupPagePermission')
|
||||
|
||||
# Create page content type
|
||||
page_content_type, created = ContentType.objects.get_or_create(
|
||||
model='page',
|
||||
app_label='wagtailcore',
|
||||
defaults={'name': 'page'}
|
||||
)
|
||||
|
||||
# Create root page
|
||||
root = Page.objects.create(
|
||||
title="Root",
|
||||
slug='root',
|
||||
content_type=page_content_type,
|
||||
path='0001',
|
||||
depth=1,
|
||||
numchild=1,
|
||||
url_path='/',
|
||||
)
|
||||
|
||||
# Create homepage
|
||||
homepage = Page.objects.create(
|
||||
title="Welcome to your new Wagtail site!",
|
||||
slug='home',
|
||||
content_type=page_content_type,
|
||||
path='00010001',
|
||||
depth=2,
|
||||
numchild=0,
|
||||
url_path='/home/',
|
||||
)
|
||||
|
||||
# Create default site
|
||||
Site.objects.create(
|
||||
hostname='localhost',
|
||||
root_page_id=homepage.id,
|
||||
is_default_site=True
|
||||
)
|
||||
|
||||
# Create auth groups
|
||||
moderators_group = Group.objects.create(name='Moderators')
|
||||
editors_group = Group.objects.create(name='Editors')
|
||||
|
||||
# Create group permissions
|
||||
GroupPagePermission.objects.create(
|
||||
group=moderators_group,
|
||||
page=root,
|
||||
permission_type='add',
|
||||
)
|
||||
GroupPagePermission.objects.create(
|
||||
group=moderators_group,
|
||||
page=root,
|
||||
permission_type='edit',
|
||||
)
|
||||
GroupPagePermission.objects.create(
|
||||
group=moderators_group,
|
||||
page=root,
|
||||
permission_type='publish',
|
||||
)
|
||||
|
||||
GroupPagePermission.objects.create(
|
||||
group=editors_group,
|
||||
page=root,
|
||||
permission_type='add',
|
||||
)
|
||||
GroupPagePermission.objects.create(
|
||||
group=editors_group,
|
||||
page=root,
|
||||
permission_type='edit',
|
||||
)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wagtailcore', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(initial_data),
|
||||
]
|
||||
0
wagtail/wagtailcore/migrations/__init__.py
Normal file
0
wagtail/wagtailcore/migrations/__init__.py
Normal file
|
|
@ -5,7 +5,7 @@ from six import string_types
|
|||
from six import StringIO
|
||||
from six.moves.urllib.parse import urlparse
|
||||
|
||||
from modelcluster.models import ClusterableModel
|
||||
from modelcluster.models import ClusterableModel, get_all_child_relations
|
||||
|
||||
from django.db import models, connection, transaction
|
||||
from django.db.models import get_model, Q
|
||||
|
|
@ -26,13 +26,11 @@ from django.utils.encoding import python_2_unicode_compatible
|
|||
|
||||
from treebeard.mp_tree import MP_Node
|
||||
|
||||
from wagtail.utils.deprecation import RemovedInWagtail06Warning
|
||||
|
||||
from wagtail.wagtailcore.utils import camelcase_to_underscore
|
||||
from wagtail.wagtailcore.query import PageQuerySet
|
||||
from wagtail.wagtailcore.url_routing import RouteResult
|
||||
|
||||
from wagtail.wagtailsearch import indexed
|
||||
from wagtail.wagtailsearch import index
|
||||
from wagtail.wagtailsearch.backends import get_search_backend
|
||||
|
||||
|
||||
|
|
@ -149,31 +147,6 @@ def get_page_types():
|
|||
return _PAGE_CONTENT_TYPES
|
||||
|
||||
|
||||
def get_leaf_page_content_type_ids():
|
||||
warnings.warn("""
|
||||
get_leaf_page_content_type_ids is deprecated, as it treats pages without an explicit subpage_types
|
||||
setting as 'leaf' pages. Code that calls get_leaf_page_content_type_ids must be rewritten to avoid
|
||||
this incorrect assumption.
|
||||
""", RemovedInWagtail06Warning)
|
||||
return [
|
||||
content_type.id
|
||||
for content_type in get_page_types()
|
||||
if not getattr(content_type.model_class(), 'subpage_types', None)
|
||||
]
|
||||
|
||||
def get_navigable_page_content_type_ids():
|
||||
warnings.warn("""
|
||||
get_navigable_page_content_type_ids is deprecated, as it treats pages without an explicit subpage_types
|
||||
setting as 'leaf' pages. Code that calls get_navigable_page_content_type_ids must be rewritten to avoid
|
||||
this incorrect assumption.
|
||||
""", RemovedInWagtail06Warning)
|
||||
return [
|
||||
content_type.id
|
||||
for content_type in get_page_types()
|
||||
if getattr(content_type.model_class(), 'subpage_types', None)
|
||||
]
|
||||
|
||||
|
||||
class PageManager(models.Manager):
|
||||
def get_queryset(self):
|
||||
return PageQuerySet(self.model).order_by('path')
|
||||
|
|
@ -274,7 +247,7 @@ class PageBase(models.base.ModelBase):
|
|||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class Page(six.with_metaclass(PageBase, MP_Node, ClusterableModel, indexed.Indexed)):
|
||||
class Page(six.with_metaclass(PageBase, MP_Node, ClusterableModel, index.Indexed)):
|
||||
title = models.CharField(max_length=255, help_text=_("The page title as you'd like it to be seen by the public"))
|
||||
slug = models.SlugField(help_text=_("The name of the page as it will appear in URLs e.g http://domain.com/blog/[my-slug]/"))
|
||||
# TODO: enforce uniqueness on slug field per parent (will have to be done at the Django
|
||||
|
|
@ -294,13 +267,13 @@ class Page(six.with_metaclass(PageBase, MP_Node, ClusterableModel, indexed.Index
|
|||
expired = models.BooleanField(default=False, editable=False)
|
||||
|
||||
search_fields = (
|
||||
indexed.SearchField('title', partial_match=True, boost=100),
|
||||
indexed.FilterField('id'),
|
||||
indexed.FilterField('live'),
|
||||
indexed.FilterField('owner'),
|
||||
indexed.FilterField('content_type'),
|
||||
indexed.FilterField('path'),
|
||||
indexed.FilterField('depth'),
|
||||
index.SearchField('title', partial_match=True, boost=100),
|
||||
index.FilterField('id'),
|
||||
index.FilterField('live'),
|
||||
index.FilterField('owner'),
|
||||
index.FilterField('content_type'),
|
||||
index.FilterField('path'),
|
||||
index.FilterField('depth'),
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
|
@ -476,14 +449,6 @@ class Page(six.with_metaclass(PageBase, MP_Node, ClusterableModel, indexed.Index
|
|||
"""
|
||||
return (not self.is_leaf()) or self.depth == 2
|
||||
|
||||
def get_other_siblings(self):
|
||||
warnings.warn(
|
||||
"The 'Page.get_other_siblings()' method has been replaced. "
|
||||
"Use 'Page.get_siblings(inclusive=False)' instead.", RemovedInWagtail06Warning)
|
||||
|
||||
# get sibling pages excluding self
|
||||
return self.get_siblings().exclude(id=self.id)
|
||||
|
||||
@property
|
||||
def full_url(self):
|
||||
"""Return the full URL (including protocol / domain) to this page, or None if it is not routable"""
|
||||
|
|
@ -653,7 +618,7 @@ class Page(six.with_metaclass(PageBase, MP_Node, ClusterableModel, indexed.Index
|
|||
|
||||
# Copy child objects
|
||||
specific_self = self.specific
|
||||
for child_relation in getattr(specific_self._meta, 'child_relations', []):
|
||||
for child_relation in get_all_child_relations(specific_self):
|
||||
parental_key_name = child_relation.field.attname
|
||||
child_objects = getattr(specific_self, child_relation.get_accessor_name(), None)
|
||||
|
||||
|
|
@ -728,15 +693,6 @@ class Page(six.with_metaclass(PageBase, MP_Node, ClusterableModel, indexed.Index
|
|||
for example, a page containing a form might have a default view of the form,
|
||||
and a post-submission 'thankyou' page
|
||||
"""
|
||||
modes = self.get_page_modes()
|
||||
if modes is not Page.DEFAULT_PREVIEW_MODES:
|
||||
# User has overriden get_page_modes instead of using preview_modes
|
||||
warnings.warn("Overriding get_page_modes is deprecated. Define a preview_modes property instead", RemovedInWagtail06Warning)
|
||||
|
||||
return modes
|
||||
|
||||
def get_page_modes(self):
|
||||
# Deprecated accessor for the preview_modes property
|
||||
return Page.DEFAULT_PREVIEW_MODES
|
||||
|
||||
@property
|
||||
|
|
@ -770,12 +726,6 @@ class Page(six.with_metaclass(PageBase, MP_Node, ClusterableModel, indexed.Index
|
|||
"""
|
||||
return self.serve(request)
|
||||
|
||||
def show_as_mode(self, mode_name):
|
||||
# Deprecated API for rendering previews. If this returns something other than None,
|
||||
# we know that a subclass of Page has overridden this, and we should try to work with
|
||||
# that response if possible.
|
||||
return None
|
||||
|
||||
def get_cached_paths(self):
|
||||
"""
|
||||
This returns a list of paths to invalidate in a frontend cache
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
import warnings
|
||||
|
||||
from wagtail.utils.deprecation import RemovedInWagtail06Warning
|
||||
|
||||
|
||||
warnings.warn(
|
||||
"The pageurl tag library has been moved to wagtailcore_tags. "
|
||||
"Use {% load wagtailcore_tags %} instead.", RemovedInWagtail06Warning)
|
||||
|
||||
|
||||
from wagtail.wagtailcore.templatetags.wagtailcore_tags import register, pageurl
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
import warnings
|
||||
|
||||
from wagtail.utils.deprecation import RemovedInWagtail06Warning
|
||||
|
||||
|
||||
warnings.warn(
|
||||
"The rich_text tag library has been moved to wagtailcore_tags. "
|
||||
"Use {% load wagtailcore_tags %} instead.", RemovedInWagtail06Warning)
|
||||
|
||||
|
||||
from wagtail.wagtailcore.templatetags.wagtailcore_tags import register, richtext
|
||||
|
|
@ -8,7 +8,7 @@ from django.utils import timezone
|
|||
|
||||
from wagtail.wagtailcore.models import Page, PageRevision
|
||||
from wagtail.wagtailcore.signals import page_published, page_unpublished
|
||||
from wagtail.tests.models import SimplePage
|
||||
from wagtail.tests.models import SimplePage, EventPage
|
||||
|
||||
|
||||
class TestFixTreeCommand(TestCase):
|
||||
|
|
@ -82,13 +82,21 @@ class TestReplaceTextCommand(TestCase):
|
|||
|
||||
def test_replace_text(self):
|
||||
# Check that the christmas page is definitely about christmas
|
||||
self.assertEqual(Page.objects.get(url_path='/home/events/christmas/').title, "Christmas")
|
||||
christmas_page = EventPage.objects.get(url_path='/home/events/christmas/')
|
||||
self.assertEqual(christmas_page.title, "Christmas")
|
||||
self.assertEqual(christmas_page.speakers.first().last_name, "Christmas")
|
||||
self.assertEqual(christmas_page.advert_placements.first().colour, "greener than a Christmas tree")
|
||||
|
||||
# Make it about easter
|
||||
self.run_command("Christmas", "Easter")
|
||||
|
||||
# Check that its now about easter
|
||||
self.assertEqual(Page.objects.get(url_path='/home/events/christmas/').title, "Easter")
|
||||
# Check that it's now about easter
|
||||
easter_page = EventPage.objects.get(url_path='/home/events/christmas/')
|
||||
self.assertEqual(easter_page.title, "Easter")
|
||||
|
||||
# Check that we also update the child objects (including advert_placements, which is defined on the superclass)
|
||||
self.assertEqual(easter_page.speakers.first().last_name, "Easter")
|
||||
self.assertEqual(easter_page.advert_placements.first().colour, "greener than a Easter tree")
|
||||
|
||||
|
||||
class TestPublishScheduledPagesCommand(TestCase):
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@ from django.test import TestCase, Client
|
|||
from django.test.utils import override_settings
|
||||
from django.http import HttpRequest, Http404
|
||||
|
||||
from wagtail.utils.deprecation import RemovedInWagtail06Warning
|
||||
|
||||
from wagtail.wagtailcore.models import Page, Site
|
||||
from wagtail.tests.models import EventPage, EventIndex, SimplePage, PageWithOldStyleRouteMethod
|
||||
|
||||
|
|
@ -282,24 +280,6 @@ class TestServeView(TestCase):
|
|||
self.assertNotContains(response, '<h1>Events</h1>')
|
||||
self.assertContains(response, '<a href="/events/christmas/">Christmas</a>')
|
||||
|
||||
|
||||
def test_old_style_routing(self):
|
||||
"""
|
||||
Test that route() methods that return an HttpResponse are correctly handled
|
||||
"""
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
response = self.client.get('/old-style-route/')
|
||||
|
||||
# Check that a RemovedInWagtail06Warning has been triggered
|
||||
self.assertEqual(len(w), 1)
|
||||
self.assertTrue(issubclass(w[-1].category, RemovedInWagtail06Warning))
|
||||
self.assertTrue("Page.route should return an instance of wagtailcore.url_routing.RouteResult" in str(w[-1].message))
|
||||
|
||||
expected_page = PageWithOldStyleRouteMethod.objects.get(url_path='/home/old-style-route/')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.context['self'], expected_page)
|
||||
self.assertEqual(response.templates[0].name, 'tests/simple_page.html')
|
||||
|
||||
def test_before_serve_hook(self):
|
||||
response = self.client.get('/events/', HTTP_USER_AGENT='GoogleBot')
|
||||
self.assertContains(response, 'bad googlebot no cookie')
|
||||
|
|
@ -420,6 +400,11 @@ class TestCopyPage(TestCase):
|
|||
# Check that the speakers weren't removed from old page
|
||||
self.assertEqual(christmas_event.speakers.count(), 1, "Child objects were removed from the original page")
|
||||
|
||||
# Check that advert placements were also copied (there's a gotcha here, since the advert_placements
|
||||
# relation is defined on Page, not EventPage)
|
||||
self.assertEqual(new_christmas_event.advert_placements.count(), 1, "Child objects defined on the superclass weren't copied")
|
||||
self.assertEqual(christmas_event.advert_placements.count(), 1, "Child objects defined on the superclass were removed from the original page")
|
||||
|
||||
def test_copy_page_copies_child_objects_with_nonspecific_class(self):
|
||||
# Get chrismas page as Page instead of EventPage
|
||||
christmas_event = Page.objects.get(url_path='/home/events/christmas/')
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
import warnings
|
||||
|
||||
from wagtail.utils.deprecation import RemovedInWagtail06Warning
|
||||
|
||||
|
||||
warnings.warn(
|
||||
"The wagtail.wagtailcore.util module has been renamed. "
|
||||
"Use wagtail.wagtailcore.utils instead.", RemovedInWagtail06Warning)
|
||||
|
||||
from .utils import *
|
||||
|
|
@ -5,8 +5,6 @@ from django.shortcuts import get_object_or_404, redirect
|
|||
from django.core.urlresolvers import reverse
|
||||
from django.conf import settings
|
||||
|
||||
from wagtail.utils.deprecation import RemovedInWagtail06Warning
|
||||
|
||||
from wagtail.wagtailcore import hooks
|
||||
from wagtail.wagtailcore.models import Page, PageViewRestriction
|
||||
from wagtail.wagtailcore.forms import PasswordPageViewRestrictionForm
|
||||
|
|
@ -19,15 +17,8 @@ def serve(request, path):
|
|||
raise Http404
|
||||
|
||||
path_components = [component for component in path.split('/') if component]
|
||||
route_result = request.site.root_page.specific.route(request, path_components)
|
||||
if isinstance(route_result, HttpResponse):
|
||||
warnings.warn(
|
||||
"Page.route should return an instance of wagtailcore.url_routing.RouteResult, not an HttpResponse",
|
||||
RemovedInWagtail06Warning
|
||||
)
|
||||
return route_result
|
||||
page, args, kwargs = request.site.root_page.specific.route(request, path_components)
|
||||
|
||||
(page, args, kwargs) = route_result
|
||||
for fn in hooks.get_hooks('before_serve_page'):
|
||||
result = fn(page, request, args, kwargs)
|
||||
if isinstance(result, HttpResponse):
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
default_app_config = 'wagtail.wagtaildocs.apps.WagtailDocsAppConfig'
|
||||
7
wagtail/wagtaildocs/apps.py
Normal file
7
wagtail/wagtaildocs/apps.py
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class WagtailDocsAppConfig(AppConfig):
|
||||
name = 'wagtail.wagtaildocs'
|
||||
label = 'wagtaildocs'
|
||||
verbose_name = "Wagtail documents"
|
||||
BIN
wagtail/wagtaildocs/locale/pt_PT/LC_MESSAGES/django.mo
Normal file
BIN
wagtail/wagtaildocs/locale/pt_PT/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
196
wagtail/wagtaildocs/locale/pt_PT/LC_MESSAGES/django.po
Normal file
196
wagtail/wagtaildocs/locale/pt_PT/LC_MESSAGES/django.po
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
# Translators:
|
||||
# Thiago Cangussu <cangussu.thg@gmail.com>, 2014
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Wagtail 0.5.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2014-08-01 16:38+0100\n"
|
||||
"PO-Revision-Date: 2014-08-03 01:53+0100\n"
|
||||
"Last-Translator: Jose Lourenco <jose@lourenco.ws>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
"X-Generator: Poedit 1.5.4\n"
|
||||
"Language: pt_PT\n"
|
||||
|
||||
#: models.py:21 templates/wagtaildocs/documents/list.html:11
|
||||
#: templates/wagtaildocs/documents/list.html:14
|
||||
#: templates/wagtaildocs/documents/usage.html:16
|
||||
msgid "Title"
|
||||
msgstr "Título"
|
||||
|
||||
#: models.py:22 templates/wagtaildocs/documents/list.html:17
|
||||
msgid "File"
|
||||
msgstr "Ficheiro"
|
||||
|
||||
#: models.py:26
|
||||
msgid "Tags"
|
||||
msgstr "Etiquetas"
|
||||
|
||||
#: wagtail_hooks.py:24 templates/wagtaildocs/documents/index.html:16
|
||||
msgid "Documents"
|
||||
msgstr "Documentos"
|
||||
|
||||
#: templates/wagtaildocs/chooser/chooser.html:2
|
||||
#: templates/wagtaildocs/edit_handlers/document_chooser_panel.html:11
|
||||
msgid "Choose a document"
|
||||
msgstr "Escolher um documento"
|
||||
|
||||
#: templates/wagtaildocs/chooser/chooser.html:7
|
||||
#: templates/wagtaildocs/chooser/chooser.html:19
|
||||
msgid "Search"
|
||||
msgstr "Procurar"
|
||||
|
||||
#: templates/wagtaildocs/chooser/chooser.html:8
|
||||
msgid "Upload"
|
||||
msgstr "Enviar"
|
||||
|
||||
#: templates/wagtaildocs/chooser/chooser.html:34
|
||||
#: templates/wagtaildocs/documents/add.html:25
|
||||
#: templates/wagtaildocs/documents/edit.html:29
|
||||
msgid "Save"
|
||||
msgstr "Guardar"
|
||||
|
||||
#: templates/wagtaildocs/chooser/results.html:5
|
||||
#: templates/wagtaildocs/documents/results.html:5
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
" There is one match\n"
|
||||
" "
|
||||
msgid_plural ""
|
||||
"\n"
|
||||
" There are %(counter)s matches\n"
|
||||
" "
|
||||
msgstr[0] ""
|
||||
"\n"
|
||||
" Existe uma correspondência\n"
|
||||
" "
|
||||
msgstr[1] ""
|
||||
"\n"
|
||||
" Existem %(counter)s correspondências\n"
|
||||
" "
|
||||
|
||||
#: templates/wagtaildocs/chooser/results.html:12
|
||||
msgid "Latest documents"
|
||||
msgstr "Últimos documentos"
|
||||
|
||||
#: templates/wagtaildocs/chooser/results.html:19
|
||||
#: templates/wagtaildocs/documents/results.html:18
|
||||
#, python-format
|
||||
msgid "Sorry, no documents match \"<em>%(query_string)s</em>\""
|
||||
msgstr "Desculpe, nenhum documento corresponde a \"<em>%(query_string)s</em>\""
|
||||
|
||||
#: templates/wagtaildocs/documents/_file_field.html:5
|
||||
msgid "Change document:"
|
||||
msgstr "Alterar documento"
|
||||
|
||||
#: templates/wagtaildocs/documents/add.html:4
|
||||
#: templates/wagtaildocs/documents/index.html:17
|
||||
msgid "Add a document"
|
||||
msgstr "Adicionar um documento"
|
||||
|
||||
#: templates/wagtaildocs/documents/add.html:15
|
||||
msgid "Add document"
|
||||
msgstr "Adicionar documento"
|
||||
|
||||
#: templates/wagtaildocs/documents/confirm_delete.html:3
|
||||
#, python-format
|
||||
msgid "Delete %(title)s"
|
||||
msgstr "Eliminar %(title)s"
|
||||
|
||||
#: templates/wagtaildocs/documents/confirm_delete.html:6
|
||||
#: templates/wagtaildocs/documents/edit.html:29
|
||||
msgid "Delete document"
|
||||
msgstr "Eliminar documento"
|
||||
|
||||
#: templates/wagtaildocs/documents/confirm_delete.html:10
|
||||
msgid "Are you sure you want to delete this document?"
|
||||
msgstr "Tem certeza que quer eliminar este documento?"
|
||||
|
||||
#: templates/wagtaildocs/documents/confirm_delete.html:13
|
||||
msgid "Yes, delete"
|
||||
msgstr "Sim, eliminar"
|
||||
|
||||
#: templates/wagtaildocs/documents/edit.html:4
|
||||
#, python-format
|
||||
msgid "Editing %(title)s"
|
||||
msgstr "Editando %(title)s"
|
||||
|
||||
#: templates/wagtaildocs/documents/edit.html:15
|
||||
msgid "Editing"
|
||||
msgstr "Editando"
|
||||
|
||||
#: templates/wagtaildocs/documents/list.html:21
|
||||
#: templates/wagtaildocs/documents/list.html:24
|
||||
msgid "Uploaded"
|
||||
msgstr "Enviado"
|
||||
|
||||
#: templates/wagtaildocs/documents/results.html:21
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You haven't uploaded any documents. Why not <a href="
|
||||
"\"%(wagtaildocs_add_document_url)s\">upload one now</a>?"
|
||||
msgstr ""
|
||||
"Ainda não enviou nenhum documento. Porque não <a href="
|
||||
"\"%(wagtaildocs_add_document_url)s\">enviar um agora</a>?"
|
||||
|
||||
#: templates/wagtaildocs/documents/usage.html:3
|
||||
#, python-format
|
||||
msgid "Usage of %(title)s"
|
||||
msgstr "Utilização de %(title)s"
|
||||
|
||||
#: templates/wagtaildocs/documents/usage.html:5
|
||||
msgid "Usage of"
|
||||
msgstr "Utilização de"
|
||||
|
||||
#: templates/wagtaildocs/documents/usage.html:17
|
||||
msgid "Parent"
|
||||
msgstr "Ascendente"
|
||||
|
||||
#: templates/wagtaildocs/documents/usage.html:18
|
||||
msgid "Type"
|
||||
msgstr "Tipo"
|
||||
|
||||
#: templates/wagtaildocs/documents/usage.html:19
|
||||
msgid "Status"
|
||||
msgstr "Estado"
|
||||
|
||||
#: templates/wagtaildocs/documents/usage.html:26
|
||||
msgid "Edit this page"
|
||||
msgstr "Editar esta ágina"
|
||||
|
||||
#: templates/wagtaildocs/edit_handlers/document_chooser_panel.html:9
|
||||
msgid "Clear choice"
|
||||
msgstr "Limpar escolha"
|
||||
|
||||
#: templates/wagtaildocs/edit_handlers/document_chooser_panel.html:10
|
||||
msgid "Choose another document"
|
||||
msgstr "Escolher outro documento"
|
||||
|
||||
#: views/documents.py:37 views/documents.py:46
|
||||
msgid "Search documents"
|
||||
msgstr "Procurar documentos"
|
||||
|
||||
#: views/documents.py:86
|
||||
msgid "Document '{0}' added."
|
||||
msgstr "Documento '{0}' adicionado."
|
||||
|
||||
#: views/documents.py:89 views/documents.py:118
|
||||
msgid "The document could not be saved due to errors."
|
||||
msgstr "O documento não pôde ser guardado devido a erros."
|
||||
|
||||
#: views/documents.py:115
|
||||
msgid "Document '{0}' updated"
|
||||
msgstr "Documento '{0}' atualizado"
|
||||
|
||||
#: views/documents.py:137
|
||||
msgid "Document '{0}' deleted."
|
||||
msgstr "Documento '{0}' apagado."
|
||||
32
wagtail/wagtaildocs/migrations/0001_initial.py
Normal file
32
wagtail/wagtaildocs/migrations/0001_initial.py
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
import taggit.managers
|
||||
from django.conf import settings
|
||||
import wagtail.wagtailadmin.taggable
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('taggit', '__latest__'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Document',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=255, verbose_name='Title')),
|
||||
('file', models.FileField(upload_to='documents', verbose_name='File')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('tags', taggit.managers.TaggableManager(to='taggit.Tag', verbose_name='Tags', help_text=None, blank=True, through='taggit.TaggedItem')),
|
||||
('uploaded_by_user', models.ForeignKey(editable=False, null=True, blank=True, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
},
|
||||
bases=(models.Model, wagtail.wagtailadmin.taggable.TagSearchable),
|
||||
),
|
||||
]
|
||||
52
wagtail/wagtaildocs/migrations/0002_initial_data.py
Normal file
52
wagtail/wagtaildocs/migrations/0002_initial_data.py
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
def add_document_permissions_to_admin_groups(apps, schema_editor):
|
||||
ContentType = apps.get_model('contenttypes.ContentType')
|
||||
Permission = apps.get_model('auth.Permission')
|
||||
Group = apps.get_model('auth.Group')
|
||||
Document = apps.get_model('wagtaildocs.Document')
|
||||
|
||||
# Get document permissions
|
||||
document_content_type, _created = ContentType.objects.get_or_create(
|
||||
model='document',
|
||||
app_label='wagtaildocs',
|
||||
defaults={'name': 'document'}
|
||||
)
|
||||
|
||||
add_document_permission, _created = Permission.objects.get_or_create(
|
||||
content_type=document_content_type,
|
||||
codename='add_document',
|
||||
defaults={'name': 'Can add document'}
|
||||
)
|
||||
change_document_permission, _created = Permission.objects.get_or_create(
|
||||
content_type=document_content_type,
|
||||
codename='change_document',
|
||||
defaults={'name': 'Can change document'}
|
||||
)
|
||||
delete_document_permission, _created = Permission.objects.get_or_create(
|
||||
content_type=document_content_type,
|
||||
codename='delete_document',
|
||||
defaults={'name': 'Can delete document'}
|
||||
)
|
||||
|
||||
# Assign it to Editors and Moderators groups
|
||||
for group in Group.objects.filter(name__in=['Editors', 'Moderators']):
|
||||
group.permissions.add(add_document_permission, change_document_permission, delete_document_permission)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wagtaildocs', '0001_initial'),
|
||||
|
||||
# Need to run wagtailcores initial data migration to make sure the groups are created
|
||||
('wagtailcore', '0002_initial_data'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(add_document_permissions_to_admin_groups),
|
||||
]
|
||||
0
wagtail/wagtaildocs/migrations/__init__.py
Normal file
0
wagtail/wagtaildocs/migrations/__init__.py
Normal file
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue