Skip to content

Commit

Permalink
Merge pull request #5282 from evildmp/tutorial-docs
Browse files Browse the repository at this point in the history
Improved introduction section
  • Loading branch information
mkoistinen committed May 12, 2016
2 parents 6b1174f + 2214296 commit 0cb47c4
Show file tree
Hide file tree
Showing 15 changed files with 367 additions and 271 deletions.
4 changes: 2 additions & 2 deletions docs/contributing/documentation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ Except for the tiniest of change, we recommend that you test them before
submitting.


##########################
**************************
Building the documentation
##########################
**************************

Follow the same steps above to fork and clone the project locally. Next, ``cd`` into the
``django-cms/docs`` and install the requirements::
Expand Down
2 changes: 2 additions & 0 deletions docs/how_to/placeholders.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.. _placeholders_outside_cms:

############################
Placeholders outside the CMS
############################
Expand Down
2 changes: 2 additions & 0 deletions docs/how_to/toolbar.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.. _toolbar_how_to:

#####################
Extending the Toolbar
#####################
Expand Down
19 changes: 9 additions & 10 deletions docs/introduction/apphooks.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.. apphooks_introduction:
########
Apphooks
########
Expand All @@ -21,15 +23,14 @@ This is the most basic example of an apphook for a django CMS application:

.. code-block:: python
from django.utils.translation import ugettext_lazy as _
from cms.app_base import CMSApp
from cms.apphook_pool import apphook_pool
from django.utils.translation import ugettext_lazy as _
class PollsApphook(CMSApp):
name = _("Polls Application") # give your application a name (required)
urls = ["polls.urls"] # link your app to url configuration(s)
app_name = "polls"
name = _("Polls Application") # give your application a name
urls = ["polls.urls"] # link it to URL configuration(s)
app_name = "polls" # set the default application namespace
apphook_pool.register(PollsApphook) # register the application
Expand All @@ -50,18 +51,16 @@ Create and save a new page, then publish it.

.. note:: Your apphook won't work until the page has been published.

In its *Advanced settings*, choose "Polls Application" from the *Application* menu, and save once
more.
In its *Advanced settings*, choose "Polls Application" from the *Application* menu. Leave the *Application instance
name* on the provided default (``polls``), and save once more.

.. image:: /introduction/images/select-application.png
:alt: select the 'Polls' application
:width: 400
:align: center

Refresh the page, and you'll find that the Polls application is now available
Refresh the page, and you'll find that the Polls application, along with any polls you have created, is now available
directly from the new django CMS page.

You can now remove the mention of the Polls application (``url(r'^polls/', include('polls.urls',
namespace='polls'))``) from your project's ``urls.py`` - it's no longer even required there.

Next, we're going to install a django-CMS-compatible third-party application.
Binary file modified docs/introduction/images/select-application.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/introduction/images/select-menu.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion docs/introduction/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ in the order presented here.

install
templates_placeholders
integrating_applications
plugins
apphooks
toolbar
Expand All @@ -47,4 +48,3 @@ If you don't have an IRC client, you can `join our IRC channel using the KiwiIRC
<https://kiwiirc.com/client/irc.freenode.net/django-cms>`_, which works pretty well.

.. _mailinglist: https://groups.google.com/forum/#!forum/django-cms

11 changes: 7 additions & 4 deletions docs/introduction/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ Please check that you have installed the
`required binary libraries <http://djangocms-installer.readthedocs.org/en/latest/libraries.html>`_
before proceeding.

Create and activate a virtual env
=================================
Create and activate a virtual environment
=========================================

::

Expand All @@ -34,6 +34,7 @@ Note that if you're using Windows, to activate the virtualenv you'll need::

env\Scripts\activate


Use the django CMS installer
============================

Expand Down Expand Up @@ -109,8 +110,10 @@ indicated with an asterisk *****).

Create a Django admin user when invited.

Start up the runserver
======================

*********************
Start up the new site
*********************

::

Expand Down
170 changes: 170 additions & 0 deletions docs/introduction/integrating_applications.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
.. _integrating_applications:

########################
Integrating applications
########################

All the following sections of this tutorial are concerned with integrating other applications into django CMS, which is
where a vast part of its power comes from.

Integrating applications doesn't just mean installing them alongside django CMS, so that they peacefully co-exist. It
means using django CMS's features to build them into a single coherent web project that speeds up the work of managing
the site, and makes possible richer and more automated publishing.

It's key to the way that django CMS integration works that **it doesn't require you to modify your other applications**
unless you want to. This is particularly important when you're using third-party applications and don't want to have to
maintain your own forked versions of them. (The only exception to this is if you decide to build django CMS features
directly into the applications themselves, for example when using :ref:`placeholders in other applications
<placeholders_outside_cms>`.)

For this tutorial, we're going to take a basic Django `opinion poll application
<https://github.com/divio/django-polls>`_ and integrate it into the CMS. So we'll install that, and create a second,
independent, *Polls/CMS Integration* application to manage the integration, leaving the first untouched.


*********************************
Install the ``polls`` application
*********************************

Install the application from its GitHub repository using ``pip``::

pip install git+http://git@github.com/divio/django-polls.git#egg=polls

Let's add this application to our project. Add ``'polls'`` to the end of ``INSTALLED_APPS`` in
your project's `settings.py` (see the note on :ref:`installed_apps` about ordering ).

Add the following line to ``urlpatterns`` in the project's ``urls.py``:

.. code-block:: python
url(r'^polls/', include('polls.urls', namespace='polls')),
Make sure this line is included **before** the line for the django-cms urls:

.. code-block:: python
url(r'^', include('cms.urls')),
django CMS's URL pattern needs to be last, because it "swallows up" anything
that hasn't already been matched by a previous pattern.

Now run the application's migrations:

.. code-block:: bash
python manage.py migrate polls
At this point you should be able to log in to the Django
admin - ``http://localhost:8000/admin/`` - and find the Polls application.

.. image:: /introduction/images/polls-admin.png
:alt: the polls application admin
:width: 400
:align: center

Create a new **Poll**, for example:

* **Question**: *Which browser do you prefer?*

**Choices**:

* *Safari*
* *Firefox*
* *Chrome*

Now if you visit ``http://localhost:8000/en/polls/``, you should be able to see the published poll
and submit a response.

.. image:: /introduction/images/polls-unintegrated.png
:alt: the polls application
:width: 400
:align: center


Improve the templates for Polls
===============================

You'll have noticed that the in the Polls application we only have minimal templates, and no navigation or styling.

Our django CMS pages on the other hand have access to a number of default templates in the project, all of which
extend one called ``base.html``. So, let's improve this by overriding the polls application's base template.

We'll do this in the *project* directory.

In ``mysite/templates``, add ``polls/base.html``, containing:

.. code-block:: html+django

{% extends 'base.html' %}

{% block content %}
{% block polls_content %}
{% endblock %}
{% endblock %}

Refresh the ``/polls/`` page again, which should now be properly integrated into the site.

.. image:: /introduction/images/polls-integrated.png
:alt: the polls application, integrated
:width: 400
:align: center



**************************************************
Set up a new ``polls_cms_integration`` application
**************************************************

So far, however, the Polls application has been integrated into the project, but not into django CMS itself. The two
applications are completely independent. They cannot make use of each other's data or functionality.

Let's create the new *Polls/CMS Integration* application where we will bring them together.


Create the application
======================

Create a new package at the project root called ``polls_cms_integration``::

python manage.py startapp polls_cms_integration

So our workspace looks like this::

env/
src/ # the django polls application is in here
polls_cms_integration/ # the newly-created application
__init__.py
admin.py
models.py
migrations.py
tests.py
views.py
mysite/
static/
project.db
requirements.txt


Add it to ``INSTALLED_APPS``
============================

Next is to integrate the ``polls_cms_integration`` application into the project.

Add ``polls_cms_integration`` to ``INSTALLED_APPS`` in ``settings.py`` - and now we're ready to use it to being
integrating Polls with django CMS. We'll start by :ref:`developing a Polls plugin <plugins_tutorial>`.

.. note::

**The project or the application?**

Earlier, we added new templates to the project. We could equally well have have added ``templates/polls/base.html``
inside ``polls_cms_integration``. After all, that's where we're going to be doing all the other integration work.

However, we'd now have an application that makes assumptions about the name of the template it should extend (see
the first line of the ``base.html`` template we created) which might not be correct for a different project.

Also, we'd have to make sure that ``polls_cms_integration`` came *before* ``polls`` in ``INSTALLED_APPS``,
otherwise the templates in ``polls_cms_integration`` would not in fact override the ones in ``polls``. Putting
them in the project guarantees that they will override those in all applications.

Either way of doing it is reasonable, as long as you understand their implications.
66 changes: 46 additions & 20 deletions docs/introduction/menu.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,14 @@ is still only determined by django CMS Pages.
We can hook into the django CMS menu system to add our own nodes to that
navigation menu.

For this we need a file called ``cms_menus.py`` in our application. Add
``cms_menus.py`` in ``polls_cms_integration/``:
***********************
Create the toolbar menu
***********************

We create the menu using a :class:`CMSAttachMenu <cms.menu_bases.CMSAttachMenu>` sub-class, and use the ``get_nodes()``
method to add the nodes.

For this we need a file called ``cms_menus.py`` in our application. Add ``cms_menus.py`` in ``polls_cms_integration/``:

.. code-block:: python
Expand All @@ -28,15 +34,16 @@ For this we need a file called ``cms_menus.py`` in our application. Add
name = _("Polls Menu") # give the menu a name this is required.
def get_nodes(self, request):
"""
This method is used to build the menu tree.
"""
nodes = []
# loop over all the Poll objects in the database
for poll in Poll.objects.all():
# create a NavigationNode based on each one
node = NavigationNode(
title=poll.question,
url=reverse('polls:detail', args=(poll.pk,)),
id=poll.pk, # unique id for this node within the menu
id=poll.pk,
)
nodes.append(node)
return nodes
Expand All @@ -53,25 +60,44 @@ What's happening here:
* ... and then create a ``NavigationNode`` object from each one
* ... and return a list of these ``NavigationNodes``

This menu class is not active until attached to the apphook we created earlier.
So open your ``cms_apps.py`` and add::

from polls_cms_integration.cms_menus import PollsMenu
************************
Apply the menu to a page
************************

This menu class is not active until attached to a page.

In the *Polls* page's *Advanced settings*, choose "Polls Menu" in the *Attached menu* field and save.

for importing ``PollsMenu`` and::
You'll now see that every Poll is represented as a node in a sub-menu for the Polls page.

menus = [PollsMenu]
.. image:: /introduction/images/select-menu.png
:alt: select 'Polls Menu'
:align: center

to the ``PollsApp`` class.

Any page that is attached to the ``Polls`` application will now have sub-menu
items for each of the Polls in the database.
Apply it automatically
======================

.. note::
Note that you could have added the menu to any page. However, we can also attach a menu like this not just to a *page*,
but to an *apphook* - so that whatever page an application is attached to, the menu will be attached to.

We'll do this in the ``cms_apps.py``, where the apphook class ``PollsApphook`` lives - the amended lines are highlighted:

.. code-block:: python
:emphasize-lines: 4, 10
from django.utils.translation import ugettext_lazy as _
from cms.app_base import CMSApp
from cms.apphook_pool import apphook_pool
from polls_cms_integration.cms_menus import PollsMenu
The point here is to illustrate the basic principles. In this actual case, note that:
class PollsApphook(CMSApp):
name = _("Polls Application") # give your application a name
urls = ["polls.urls"] # link it to URL configuration(s)
app_name = "polls" # set the default application namespace
menus = [PollsMenu] # set a menu for this apphook
* If you're going to use sub-pages, you'll need to improve the menu styling to make it work a
bit better.
* Since the Polls page lists all the Polls in it anyway, this isn't really the most practical
addition to the menu.
Any page that is attached to the ``Polls`` application will now have sub-menu items for each of the Polls in the
database. It doesn't stop you from *also* adding menus to pages manually, but guarantees that they will appear on the
Polls page at least.

0 comments on commit 0cb47c4

Please sign in to comment.