Browse Source

Merge branch 'master' of github.com:wagtail/bakerydemo

Arnar Tumi Þorsteinsson 8 years ago
parent
commit
dba8b86421

+ 7 - 14
bakerydemo/base/blocks.py

@@ -1,14 +1,7 @@
 from wagtail.wagtailimages.blocks import ImageChooserBlock
 from wagtail.wagtailembeds.blocks import EmbedBlock
 from wagtail.wagtailcore.blocks import (
-    StructBlock,
-    TextBlock,
-    StreamBlock,
-    RichTextBlock,
-    CharBlock,
-    ListBlock,
-    ChoiceBlock,
-    PageChooserBlock
+    CharBlock, ChoiceBlock, RichTextBlock, StreamBlock, StructBlock, TextBlock,
 )
 
 
@@ -25,11 +18,11 @@ class ImageBlock(StructBlock):
 class HeadingBlock(StructBlock):
     heading_text = CharBlock(classname="title", required=True)
     size = ChoiceBlock(choices=[
-            ('', 'Select a header size'),
-            ('h2', 'H2'),
-            ('h3', 'H3'),
-            ('h4', 'H4')
-        ], blank=True, required=False)
+        ('', 'Select a header size'),
+        ('h2', 'H2'),
+        ('h3', 'H3'),
+        ('h4', 'H4')
+    ], blank=True, required=False)
 
     class Meta:
         icon = "title"
@@ -39,7 +32,7 @@ class HeadingBlock(StructBlock):
 class BlockQuote(StructBlock):
     text = TextBlock(),
     attribute_name = CharBlock(
-            blank=True, required=False, label='e.g. Guy Picciotto')
+        blank=True, required=False, label='e.g. Guy Picciotto')
 
     class Meta:
         icon = "fa-quote-left"

+ 23 - 0
bakerydemo/base/migrations/0003_footertext.py

@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.5 on 2017-02-10 13:38
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import wagtail.wagtailcore.fields
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('base', '0002_auto_20170210_1217'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='FooterText',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('body', wagtail.wagtailcore.fields.RichTextField()),
+            ],
+        ),
+    ]

+ 41 - 45
bakerydemo/base/models.py

@@ -1,28 +1,24 @@
 from __future__ import unicode_literals
 
 from django.db import models
-from django.db.utils import OperationalError
 
 from modelcluster.fields import ParentalKey
 from modelcluster.models import ClusterableModel
-from wagtail.wagtailcore.models import Page, Orderable, Collection
-from wagtail.wagtailsearch import index
-from wagtail.wagtailimages.edit_handlers import ImageChooserPanel
-from wagtail.wagtailcore.fields import StreamField, RichTextField
+
+from wagtail.contrib.modeladmin.options import (
+    ModelAdmin, ModelAdminGroup, modeladmin_register)
 from wagtail.wagtailadmin.edit_handlers import (
-        FieldPanel,
-        InlinePanel,
-        FieldRowPanel,
-        StreamFieldPanel,
-        MultiFieldPanel,
-        PageChooserPanel
-        )
+    FieldPanel, FieldRowPanel, InlinePanel, MultiFieldPanel,
+    PageChooserPanel, StreamFieldPanel,
+)
+from wagtail.wagtailcore.fields import RichTextField, StreamField
+from wagtail.wagtailcore.models import Collection, Orderable, Page
+from wagtail.wagtailforms.models import AbstractEmailForm, AbstractFormField
+from wagtail.wagtailimages.edit_handlers import ImageChooserPanel
+from wagtail.wagtailsearch import index
 from wagtail.wagtailsnippets.models import register_snippet
-from wagtail.wagtailsnippets.edit_handlers import SnippetChooserPanel
+
 from .blocks import BaseStreamBlock
-from wagtail.wagtailforms.models import AbstractEmailForm, AbstractFormField
-from wagtail.contrib.modeladmin.options import (
-    ModelAdmin, ModelAdminGroup, modeladmin_register)
 
 
 @register_snippet
@@ -53,21 +49,36 @@ class People(ClusterableModel):
 
     @property
     def thumb_image(self):
-       # fail silently if there is no profile pic or the rendition file can't
-       # be found. Note @richbrennan worked out how to do this...
-       try:
-           return self.image.get_rendition('fill-50x50').img_tag()
-       except:
-           return ''
+        # fail silently if there is no profile pic or the rendition file can't
+        # be found. Note @richbrennan worked out how to do this...
+        try:
+            return self.image.get_rendition('fill-50x50').img_tag()
+        except:
+            return ''
 
     def __str__(self):
-        return self.first_name + " " + self.last_name
+        return '{} {}'.format(self.first_name, self.last_name)
 
     class Meta:
         verbose_name = 'Person'
         verbose_name_plural = 'People'
 
 
+@register_snippet
+class FooterText(models.Model):
+    body = RichTextField()
+
+    panels = [
+        FieldPanel('body'),
+    ]
+
+    def __str__(self):
+        return "Footer text"
+
+    class Meta:
+        verbose_name_plural = 'Footer Text'
+
+
 class AboutLocationRelationship(Orderable, models.Model):
     """
     This defines the relationship between the `LocationPage` within the `locations`
@@ -100,7 +111,7 @@ class AboutPage(Page):
 
     body = StreamField(
         BaseStreamBlock(), verbose_name="About page detail", blank=True
-        )
+    )
     # We've defined the StreamBlock() within blocks.py that we've imported on
     # line 12. Defining it in a different file gives us consistency across the
     # site, though StreamFields _can_ be created on a per model basis if you
@@ -110,10 +121,10 @@ class AboutPage(Page):
         ImageChooserPanel('image'),
         StreamFieldPanel('body'),
         InlinePanel(
-           'location_about_relationship',
-           label='Locations',
-           min_num=None
-           ),
+            'location_about_relationship',
+            label='Locations',
+            min_num=None
+        ),
     ]
 
     # parent_page_types = [
@@ -128,22 +139,6 @@ class AboutPage(Page):
     # api_fields = ['image', 'body']
 
 
-def getImageCollections():
-    # We return all collections to a list that don't have the name root.
-    try:
-        collection_images = [(
-            collection.id, collection.name
-            ) for collection in Collection.objects.all().exclude(
-            name='Root'
-            )]
-        return collection_images
-    except:
-        return [('', '')]
-
-    def __str__(self):
-        return self.title
-
-
 class HomePage(Page):
     """
     The Home Page
@@ -159,7 +154,7 @@ class HomePage(Page):
 
     body = StreamField(
         BaseStreamBlock(), verbose_name="Home page detail", blank=True
-        )
+    )
 
     content_panels = Page.content_panels + [
         ImageChooserPanel('image'),
@@ -254,6 +249,7 @@ class MyModelAdminGroup(ModelAdminGroup):
     menu_order = 200  # will put in 3rd place (000 being 1st, 100 2nd)
     items = (PeopleModelAdmin,)
 
+
 # When using a ModelAdminGroup class to group several ModelAdmin classes together,
 # you only need to register the ModelAdminGroup class with Wagtail:
 modeladmin_register(MyModelAdminGroup)

+ 13 - 2
bakerydemo/base/templatetags/navigation_tags.py

@@ -1,8 +1,10 @@
 from django import template
-from django.template import Template
-from django.utils.http import urlencode
+
 from wagtail.wagtailcore.models import Page
 
+from bakerydemo.base.models import FooterText
+
+
 register = template.Library()
 # https://docs.djangoproject.com/en/1.9/howto/custom-template-tags/
 
@@ -87,3 +89,12 @@ def breadcrumbs(context):
         'ancestors': ancestors,
         'request': context['request'],
     }
+
+
+@register.inclusion_tag('base/include/footer.html', takes_context=True)
+def get_footer_text(context):
+    footer_text = FooterText.objects.first().body
+
+    return {
+        'footer_text': footer_text,
+    }

+ 4 - 6
bakerydemo/blog/models.py

@@ -4,22 +4,20 @@ from django.contrib import messages
 from django.db import models
 from django.shortcuts import redirect, render
 
-from modelcluster.fields import ParentalKey
 from modelcluster.contrib.taggit import ClusterTaggableManager
+from modelcluster.fields import ParentalKey
 
 from taggit.models import Tag, TaggedItemBase
 
 from wagtail.contrib.wagtailroutablepage.models import RoutablePageMixin, route
 from wagtail.wagtailadmin.edit_handlers import (
-    FieldPanel,
-    InlinePanel,
-    StreamFieldPanel,
+    FieldPanel, InlinePanel, StreamFieldPanel,
 )
-from wagtail.wagtailimages.edit_handlers import ImageChooserPanel
 from wagtail.wagtailcore.fields import StreamField
 from wagtail.wagtailcore.models import Page, Orderable
-from wagtail.wagtailsnippets.edit_handlers import SnippetChooserPanel
+from wagtail.wagtailimages.edit_handlers import ImageChooserPanel
 from wagtail.wagtailsearch import index
+from wagtail.wagtailsnippets.edit_handlers import SnippetChooserPanel
 
 from bakerydemo.base.blocks import BaseStreamBlock
 

+ 5 - 7
bakerydemo/breads/models.py

@@ -1,12 +1,12 @@
 from django.db import models
 
-from wagtail.wagtailcore.models import Page
-from wagtail.wagtailcore.fields import StreamField
 from wagtail.wagtailadmin.edit_handlers import FieldPanel, StreamFieldPanel
+from wagtail.wagtailcore.fields import StreamField
+from wagtail.wagtailcore.models import Page
 
+from wagtail.wagtailcore import blocks
 from wagtail.wagtailimages.edit_handlers import ImageChooserPanel
 from wagtail.wagtailsearch import index
-from wagtail.wagtailcore import blocks
 from wagtail.wagtailsnippets.models import register_snippet
 
 
@@ -55,7 +55,7 @@ class BreadPage(Page):
         on_delete=models.SET_NULL,
         null=True,
         blank=True,
-        )
+    )
     description = StreamField([
         ('heading', blocks.CharBlock(classname="full title")),
         ('paragraph', blocks.RichTextBlock()),
@@ -89,9 +89,7 @@ class BreadPage(Page):
         index.SearchField('description'),
     ]
 
-    parent_page_types = [
-       'BreadsIndexPage'
-    ]
+    parent_page_types = ['BreadsIndexPage']
 
     api_fields = ['title', 'bread_type', 'origin', 'image']
 

+ 1 - 3
bakerydemo/locations/models.py

@@ -121,6 +121,4 @@ class LocationPage(Page):
         context['long'] = self.lat_long.split(",")[1]
         return context
 
-    parent_page_types = [
-       'LocationsIndexPage'
-    ]
+    parent_page_types = ['LocationsIndexPage']

+ 1 - 2
bakerydemo/search/views.py

@@ -1,5 +1,5 @@
-from django.shortcuts import render
 from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
+from django.shortcuts import render
 
 from wagtail.wagtailcore.models import Page
 from wagtail.wagtailsearch.models import Query
@@ -7,7 +7,6 @@ from wagtail.wagtailsearch.models import Query
 from bakerydemo.blog.models import BlogPage
 from bakerydemo.breads.models import BreadPage
 from bakerydemo.locations.models import LocationPage
-from bakerydemo.base.models import People
 
 
 def search(request):

+ 2 - 10
bakerydemo/settings/dev.py

@@ -1,19 +1,11 @@
 from .base import *
 
-
-# SECURITY WARNING: don't run with debug turned on in production!
 DEBUG = True
-TEMPLATES[0]['OPTIONS']['debug'] = True
-
-# SECURITY WARNING: keep the secret key used in production secret!
-SECRET_KEY = 'CHANGEME!!!'
-
-INTERNAL_IPS = ('127.0.0.1', '10.0.2.2')
-
-BASE_URL = 'http://localhost:8000'
 
 EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
 
+# BASE_URL required for notification emails
+BASE_URL = 'http://localhost:8000'
 
 try:
     from .local import *

+ 0 - 175
bakerydemo/settings/production.py

@@ -1,175 +0,0 @@
-import os
-import dj_database_url
-
-from .base import *
-
-# Do not set SECRET_KEY, Postgres or LDAP password or any other sensitive data here.
-# Instead, use environment variables or create a local.py file on the server.
-
-# Disable debug mode
-DEBUG = False
-TEMPLATES[0]['OPTIONS']['debug'] = False
-
-
-# Configuration from environment variables
-# Alternatively, you can set these in a local.py file on the server
-
-env = os.environ.copy()
-
-# On Torchbox servers, many environment variables are prefixed with "CFG_"
-for key, value in os.environ.items():
-    if key.startswith('CFG_'):
-        env[key[4:]] = value
-
-
-# Basic configuration
-
-APP_NAME = env.get('APP_NAME', 'bakerydemo')
-
-if 'SECRET_KEY' in env:
-    SECRET_KEY = env['SECRET_KEY']
-
-if 'ALLOWED_HOSTS' in env:
-    ALLOWED_HOSTS = env['ALLOWED_HOSTS'].split(',')
-
-if 'PRIMARY_HOST' in env:
-    BASE_URL = 'http://%s/' % env['PRIMARY_HOST']
-
-if 'SERVER_EMAIL' in env:
-    SERVER_EMAIL = env['SERVER_EMAIL']
-
-if 'CACHE_PURGE_URL' in env:
-    INSTALLED_APPS += ( 'wagtail.contrib.wagtailfrontendcache', )
-    WAGTAILFRONTENDCACHE = {
-        'default': {
-            'BACKEND': 'wagtail.contrib.wagtailfrontendcache.backends.HTTPBackend',
-            'LOCATION': env['CACHE_PURGE_URL'],
-        },
-    }
-
-if 'STATIC_URL' in env:
-    STATIC_URL = env['STATIC_URL']
-
-if 'STATIC_DIR' in env:
-    STATIC_ROOT = env['STATIC_DIR']
-
-if 'MEDIA_URL' in env:
-    MEDIA_URL = env['MEDIA_URL']
-
-if 'MEDIA_DIR' in env:
-    MEDIA_ROOT = env['MEDIA_DIR']
-
-
-# Database
-
-if 'DATABASE_URL' in os.environ:
-    DATABASES = {'default': dj_database_url.config()}
-
-else:
-    DATABASES = {
-        'default': {
-            'ENGINE': 'django.db.backends.postgresql_psycopg2',
-            'NAME': env.get('PGDATABASE', APP_NAME),
-            'CONN_MAX_AGE': 600,  # number of seconds database connections should persist for
-
-            # User, host and port can be configured by the PGUSER, PGHOST and
-            # PGPORT environment variables (these get picked up by libpq).
-        }
-    }
-
-
-# Elasticsearch
-
-if 'ELASTICSEARCH_URL' in env:
-    WAGTAILSEARCH_BACKENDS = {
-        'default': {
-            'BACKEND': 'wagtail.wagtailsearch.backends.elasticsearch.ElasticSearch',
-            'URLS': [env['ELASTICSEARCH_URL']],
-            'INDEX': APP_NAME,
-            'ATOMIC_REBUILD': True,
-        },
-    }
-
-
-# Logging
-
-LOGGING = {
-    'version': 1,
-    'disable_existing_loggers': False,
-    'handlers': {
-        'mail_admins': {
-            'level': 'ERROR',
-            'class': 'django.utils.log.AdminEmailHandler',
-        },
-    },
-    'formatters': {
-        'default': {
-            'verbose': '[%(asctime)s] (%(process)d/%(thread)d) %(name)s %(levelname)s: %(message)s'
-        }
-    },
-    'loggers': {
-        'bakerydemo': {
-            'handlers':     [],
-            'level':        'INFO',
-            'propagate':    False,
-            'formatter':    'verbose',
-        },
-        'wagtail': {
-            'handlers':     [],
-            'level':        'INFO',
-            'propagate':    False,
-            'formatter':    'verbose',
-        },
-        'django.request': {
-            'handlers':     ['mail_admins'],
-            'level':        'ERROR',
-            'propagate':    False,
-            'formatter':    'verbose',
-        },
-        'django.security': {
-            'handlers':     ['mail_admins'],
-            'level':        'ERROR',
-            'propagate':    False,
-            'formatter':    'verbose',
-        },
-    },
-}
-
-
-if 'LOG_DIR' in env:
-    # bakerydemo log
-    LOGGING['handlers']['bakerydemo_file'] = {
-        'level':        'INFO',
-        'class':        'cloghandler.ConcurrentRotatingFileHandler',
-        'filename':     os.path.join(env['LOG_DIR'], 'bakerydemo.log'),
-        'maxBytes':     5242880, # 5MB
-        'backupCount':  5
-    }
-    LOGGING['loggers']['wagtail']['handlers'].append('bakerydemo_file')
-
-    # Wagtail log
-    LOGGING['handlers']['wagtail_file'] = {
-        'level':        'INFO',
-        'class':        'cloghandler.ConcurrentRotatingFileHandler',
-        'filename':     os.path.join(env['LOG_DIR'], 'wagtail.log'),
-        'maxBytes':     5242880, # 5MB
-        'backupCount':  5
-    }
-    LOGGING['loggers']['wagtail']['handlers'].append('wagtail_file')
-
-    # Error log
-    LOGGING['handlers']['errors_file'] = {
-        'level':        'ERROR',
-        'class':        'cloghandler.ConcurrentRotatingFileHandler',
-        'filename':     os.path.join(env['LOG_DIR'], 'error.log'),
-        'maxBytes':     5242880, # 5MB
-        'backupCount':  5
-    }
-    LOGGING['loggers']['django.request']['handlers'].append('errors_file')
-    LOGGING['loggers']['django.security']['handlers'].append('errors_file')
-
-
-try:
-    from .local import *
-except ImportError:
-    pass

+ 4 - 4
bakerydemo/templates/about_page.html

@@ -2,12 +2,12 @@
 {% load wagtailimages_tags %}
 
 {% block content %}
-	{{ page.title }}
+    {{ page.title }}
 
     <div class="image">
         {% image page.image width-500 as photo %}
               <img src="{{ photo.url }}" width="{{ photo.width }}" height="{{ photo.height }}" alt="{{ photo.alt }}" />
-	</div>
+    </div>
 
-	{{ page.body }}
-{% endblock content %}
+    {{ page.body }}
+{% endblock content %}

+ 1 - 1
bakerydemo/templates/base.html

@@ -165,7 +165,7 @@
                             </a>
                         </li>
                     </ul>
-                    <p class="copyright text-muted">Copyright &copy; Your Website 2016</p>
+                    <p class="copyright text-muted">{% get_footer_text %}</p>
                 </div>
             </div>
         </div>

+ 1 - 1
bakerydemo/templates/base/about_page.html

@@ -10,4 +10,4 @@
     </div>
 
     {{ page.body }}
-{% endblock content %}
+{% endblock content %}

+ 1 - 0
bakerydemo/templates/base/form_page.html

@@ -1,5 +1,6 @@
 {% extends "base.html" %}
 {% load wagtailcore_tags %}
+
 {% block content %}
     {{ page.intro|richtext }}
 

+ 1 - 0
bakerydemo/templates/base/form_page_landing.html

@@ -1,5 +1,6 @@
 {% extends "base.html" %}
 {% load wagtailcore_tags %}
+
 {% block content %}
     <h1>{{ page.title }}</h1>
     {{ page.thank_you_text|richtext }}

+ 4 - 0
bakerydemo/templates/base/include/footer.html

@@ -0,0 +1,4 @@
+{% load wagtailcore_tags %}
+
+
+{{ footer_text|richtext }}

+ 8 - 8
bakerydemo/templates/blocks/heading_block.html

@@ -1,15 +1,15 @@
 {% if self.size == 'h2' %}
-	    <h2>{{ self.heading_text }}</h2>
+        <h2>{{ self.heading_text }}</h2>
 
-	{% elif self.size == 'h3' %}
-	    <h3>{{ self.heading_text }}</h3>
+    {% elif self.size == 'h3' %}
+        <h3>{{ self.heading_text }}</h3>
 
-	{% elif self.size == 'h4' %}
-	    <h4>{{ self.heading_text }}</h4>
+    {% elif self.size == 'h4' %}
+        <h4>{{ self.heading_text }}</h4>
 
 {% endif %}
 
 {% comment %}
-	Content is coming from the StandardBlock StreamField
-	class within `blocks.py`
-{% endcomment %}
+    Content is coming from the StandardBlock StreamField
+    class within `blocks.py`
+{% endcomment %}

+ 2 - 4
bakerydemo/templates/blocks/image_block.html

@@ -1,8 +1,6 @@
 {% load wagtailimages_tags %}
 
-
-
 <figure>
-  {% image self.image fill-600x600 %}
-      <figcaption>{{ self.caption }} - {{ self.attribution }}</figcaption>
+    {% image self.image fill-600x600 %}
+    <figcaption>{{ self.caption }} - {{ self.attribution }}</figcaption>
 </figure>

+ 1 - 1
bakerydemo/templates/blocks/paragraph_block.html

@@ -1 +1 @@
-        {{ self }}
+{{ self }}

+ 0 - 1
bakerydemo/templates/blog/blog_index_page.html

@@ -3,7 +3,6 @@
 
 {% block content %}
     {{ page.title }}
-
     {% for blog in blogs %}
         <div>
             <h2><a href="{{ blog.full_url }}">{{ blog.title }}</a></h2>

+ 1 - 2
bakerydemo/templates/breads/breads_index_page.html

@@ -3,8 +3,7 @@
 
 {% block content %}
     {{ page.title }}
-
     {% for bread in breads %}
         <div><a href="{{ bread.slug }}">{{ bread.title }}</a></div>
     {% endfor %}
-{% endblock content %}
+{% endblock content %}

+ 8 - 0
bakerydemo/templates/locations/location_page.html

@@ -33,6 +33,14 @@
           },
           zoom: 8
         });
+        var marker = new google.maps.Marker({
+          position: {
+              lat: {{lat}},
+              lng: {{long}}
+          },
+          map: map,
+          title: '{{page.title}}'
+        });
       }
     </script>
     <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyD31CT9P9KxvNUJOwDq2kcFEIG8ADgaFgw&callback=initMap" async defer></script>

+ 0 - 1
bakerydemo/templates/search/search_results.html

@@ -4,7 +4,6 @@
 {% block title %}Search{% if search_results %} results{% endif %}{% endblock %}
 
 {% block content %}
-
     <h1>
         Search results{% if request.GET.query %} for “{{ request.GET.query }}”{% endif %}
     </h1>

+ 0 - 4
bakerydemo/templates/tags/sidebar_menu.html

@@ -2,13 +2,10 @@
 {% get_site_root as site_root %}
 
 {% if calling_page|has_protocol_parent and calling_page.content_type.model == 'standardpage' %}
-
   <div class="off-canvas position-left reveal-for-large bla" id="offCanvasLeft" data-off-canvas>
     {% protocol_menu calling_page=calling_page %}
   </div>
-
 {% elif ancestor.has_children %}
-
   <div class="off-canvas position-left reveal-for-large" id="offCanvasLeft" data-off-canvas>
     <nav class="sidebar-nav">
       <h3>In this section</h3>
@@ -32,5 +29,4 @@
       </ul>
     </nav>
   </div>
-
 {% endif %}

+ 0 - 1
bakerydemo/templates/tags/top_menu.html

@@ -1,7 +1,6 @@
 {% load navigation_tags wagtailcore_tags %}
 {% get_site_root as site_root %}
 
-
 <div class="navigation-bar">
     <ul id="main-menu">
       {% for menuitem in menuitems %}

+ 1 - 0
bakerydemo/templates/tags/top_menu_children.html

@@ -1,4 +1,5 @@
 {% load navigation_tags wagtailcore_tags %}
+
 <ul class="submenu">
   {% for child in menuitems_children %}
     <li><a href="{% pageurl child %}">{{ child.title }}</a></li>

+ 16 - 4
readme.md

@@ -3,11 +3,16 @@ Wagtail demo project
 
 This is a demonstration project for [Wagtail CMS](http://wagtail.io).
 
-*We do __not__ recommend using this project to start your own site*. This project is only to provide some examples of implementing common features, it is not an exemplar of Django or Wagtail best practice.
+*We do __not__ recommend using this project to start your own site*. This project is only to provide some examples of
+implementing common features, it is not an exemplar of Django or Wagtail best practice.
 
-If you're reasonably new to Python/Django, we suggest you run this project on a Virtual Machine using Vagrant, which helps  resolve common software dependency issues. However for more experienced developers, instructions to start this project without Vagrant follow below.
+If you're reasonably new to Python/Django, we suggest you run this project on a Virtual Machine using Vagrant, which
+helps  resolve common software dependency issues. However for more experienced developers, instructions to start this
+project without Vagrant follow below.
 
-Once you're familiar with the examples in this project and you want to start a real site, we strongly recommend running the ``wagtail start`` command in a fresh virtual environment, explained in the [Wagtail CMS Documentation](http://wagtail.readthedocs.org/en/latest/getting_started/).
+Once you're familiar with the examples in this project and you want to start a real site, we strongly recommend running
+the ``wagtail start`` command in a fresh virtual environment, explained in the
+[Wagtail CMS Documentation](http://wagtail.readthedocs.org/en/latest/getting_started/).
 
 Setup with Vagrant
 ------------------
@@ -26,7 +31,10 @@ Run the following commands:
       (then, within the SSH session:)
     ./manage.py runserver 0.0.0.0:8000
 
-The demo site will now be accessible at [http://localhost:8000/](http://localhost:8000/) and the Wagtail admin interface at [http://localhost:8000/admin/](http://localhost:8000/admin/) . Log into the admin with the credentials ``admin / changeme``.
+The demo site will now be accessible at [http://localhost:8000/](http://localhost:8000/) and the Wagtail admin
+interface at [http://localhost:8000/admin/](http://localhost:8000/admin/).
+
+Log into the admin with the credentials ``admin / changeme``.
 
 Setup without Vagrant
 -----
@@ -44,9 +52,13 @@ With PIP installed run the following commands:
     pip install -r requirements.txt
     ./manage.py migrate
     ./manage.py load_initial_data
+      (if you want a custom superuser:)
     ./manage.py createsuperuser
     ./manage.py runserver
 
+Log into the admin with the credentials ``admin / changeme`` or, if you created a superuser,
+with the custom superuser credentials.
+
 ### Note on demo search:
 
 Because we can't (easily) use ElasticSearch for this demo, we use wagtail's native DB search.