Feb 012017
 

I coded XML.com in Wagtail, a CMS based on Django. It works well for my needs and I like Python as a programming language. One of the big reasons I like Wagtail is that it includes a powerful enough but not overly complicated workflow with roles and a built-in moderation and preview system.

But, I wanted a system where people could submit news items that would go into the moderation queue without needing to sign up for a login first. Fortunately, Wagtail makes that possible, and there’s a nice article by Erin Mullaney at Wagtail: 2 Steps for Adding Pages Outside of the CMS that details all the steps you need. It all worked nicely in more recent versions of Wagtail (thanks, Erin!) except for one part, the notification that the news item is in the moderation queue. That wasn’t a stop-ship item, so XML.com launched without those emails working.

I’ve now found the source of the problem. It turns out that when you submit a news item in this way, it doesn’t have a login identity attached to it (obviously, since there isn’t one). The send_notification function that sends the email uses templates, and these templates use the login identity of the author in the body of the email. Since that doesn’t exist, the whole function fails.

That means the solution is easy. The affected templates are wagtailadmin/notifications/submitted.txt and wagtailadmin/notifications/submitted.html, and Wagtail lets you customize the admin templates. I put my customized admin templates into a utils application, which contains all my utilities for the site. My utils/templates/wagtailadmin/notifications/submitted.txt file now has the content

{% extends 'wagtailadmin/notifications/submitted.txt' %}
{% load i18n %}

{% block content %}
{% blocktrans with page=revision.page|safe %}The page "{{ page }}" has been submitted for moderation.{% endblocktrans %}

{% trans "You can preview the page here:" %} {{ settings.BASE_URL }}{% url 'wagtailadmin_pages:preview_for_moderation' revision.id %}
{% trans "You can edit the page here:" %} {{ settings.BASE_URL }}{% url 'wagtailadmin_pages:edit' revision.page.id %}
{% endblock %}

Similar changes are necessary for the wagtailadmin/notifications/submitted.html file if you want to send HTML emails instead.

May 102016
 

If you read the documentation closely enough, of course all the information is there. Getting the order of operations right, however, can cause the odd issue.

Developing Django apps means applying migrations, and those don’t always do what’s expected. In that case, you can roll back to the n-1 migration by using ./manage.py migrate [app_label] {n-1_migration_label}, then delete the nth migration, then edit the models.py to try again.

To clean up the database from some third-party app you decide you don’t want after all, you use ./manage.py migrate [app_label] zero to get rid of the migrations from that app. You have to run this before deleting the app from your settings.py file.

Apr 222016
 

I discovered another issue while deploying to PythonAnywhere (maybe it’s applicable to other PAAS providers as well).

There was an odd ImportError when running manage.py. In the specific case I had, it showed up when running the tests with coverage: from Unipath import Path ImportError: No module named ‘Unipath’. It turned out I hadn’t installed coverage in the virtual environment, which meant the system was using the default one. Installing coverage in the virtual environment as well fixed the problem.

Apr 212016
 

A checklist for moving a Django-Wagtail project to PythonAnywhere. There is documentation on the PythonAnywhere site; mine includes things I forget.

Setup: development and testing on my laptop, staging and production on PythonAnywhere.

The help files are pretty good, but I need my own checklist. Right now I’m in the staging mode, but at some stage I’ll be moving to production. No point figuring out the same things twice!

  1. Develop on laptop in a virtualenv. Push commits regularly to bitbucket account. At some stage squash the migrations and clean those up. Four sets of settings: dev, testing, staging, production.
  2. Set up account on PythonAnywhere that allows the use of Postgres (it’s an add-on to a custom plan).
  3. Create virtualenv and set up staging web app. Delete virtualenv when you realise you didn’t use the right version of Python and the default is 2.7, not 3.5. Recreate the virtualenv with python 3.5.
  4. Clone the repository (using the ssh-keygen instructions). Redirect the public key to a file so you can copy it without line-breaks getting in the way.
  5. pip install -r requirements/production.txt (including psycopg2, which I didn’t need for development).
  6. Create the Postgres server, user, and database Don’t forget a strong password for the user (owner of the project database).
  7. Update the settings file with the database settings.
  8. Set the environment variables for the settings and the secret key (generator).
  9. Attempt to apply the migrations. This will show where you made mistakes on all the preceding steps.
  10. Fix the mistakes. Reload the web app to see if anything shows up.
  11. Set up the static file server. Check the static files are being served correctly.
  12. Create the Django superuser and log in.

The next step is data, of course.