Return to referer on cancel -z3c.form

Return to referer when pressing cancel on z3c.form

The default cancel action on is to just clear the form. This is hardly what you need in many cases.

Probably you will want to direct the user on something similar to a thank you page, or maybe just close a containing pop up.

In this post I will show you how to override the default behavior in order to redirect the user to the referer.

Generally speaking you can get the HTTP referer from your zope request.

The first thing to do is to store the referer url in to a form field. This can be done adding a URI field on your form.

from z3c.form.field import Fields
from zope.schema import URI

class MyForm(Form):

    def updateFields(self):
        ''' Adds a referer that can be used when a cancel button is pressed
        super(AddForm, self).updateFields()
        referer = URI(
            default=self.request.get('HTTP_REFERER', ''),
        self.fields += Fields(referer)

In addition we want to have that field hidden.

To set up the referer widget, we override the updateWidgets method:

    def updateWidgets(self):
        ''' Adds a referer to be used when a cancel button is pressed
        super(AddForm, self).updateWidgets()
        self.widgets['referer'].mode = 'hidden'

The default behavior when you submit your form is to traverse to your next_url.

    def nextURL(self):
        ''' The next URL
        if self.immediate_view is not None:
            return self.immediate_view
        referer = self.request.get('form.widgets.referer', '')  # custom code
        if referer:                                             # custom code
            return referer                                      # custom code
        return self.context.absolute_url()

The three lines check if we have an immediate_view instance property. If we have it, it means a content has been created.

Note: it would be better to push the referer to that instance property.

What to do when I want to write a new blog post

I should update this site more often :)

This is mainly a note for myself...

Usually it takes a long time between two of my posts, so probably many Nikola releases appeared.

So before starting I think it is good idea to upgrade :p

What I do is something like this:

. bin/activate
pip install -U Nikola
pip freeze > requirements.txt
git diff

Yeah, I know, I should add this to a Makefile ;)

Then in one console I start nikola auto:

cd ale-rt
nikola auto

And on another one I add a new post:

nikola new_post -f markdown -2 -t "What to do when I want to write a new blog post"

After that, if everything goes right I push my commits.

Notes on Plone5 migration

Plone 5.0b1 is out

Caveat: This is work in progress.

The First beta of Plone 5 is in the wild and is performing really good.

It is time to start migrating our products.

On this page I am going to link all the resources I am finding about porting code from Plone 4 to Plone 5.

Changed imports

I will try to keep this list up to date.

Import zope IIntIds from zope.intid (was
-from import IIntIds
+from zope.intid.interfaces import IIntIds

Products you will not need anymore

There a re some products that have been included/superseeded by Plone5 default packages.

Here a list of those and some instructions on how to remove them.


Many of my sites where using wildcard.foldercontents.

This is enough in most cases (not all):

  • remove wildcard.foldercontents your buildouts
  • remove wildcard.foldercontents in your files
  • remove <dependency>profile-wildcard.foldercontents:default</dependency> in your metadata.xml files

In some other case you may have to search deeper in your code (python imports, template customizations, ...)

Theme migration

If your Plone 4 theme was based on "Sunburst Theme" remember to modify this: it should be based on "Plone Default".

You should do something similar:

- <skin-path name="My Site Theme" based-on="Sunburst Theme">
+ <skin-path name="My Site Theme" based-on="Plone Default">

Portlets compatibility

Do you want to port your portlets to Plone5? You have to port the to the new z3c.form machinery. Luckily this is really easy

How to exclude pages from Nikola sitemap

Short answer

You should have a line like this in your file:

ROBOTS_EXCLUSIONS = ["/404.html", "/*/404.html"]

As you can see you the exclusion list works with both exact URLs or expressions containing wildcards.

Long answer — tl;dr

When you publish a site on github pages you can add a 404.html. That page will be served each time you look for a not existing resource.

This can happen, for example, because you followed a broken link, mistyped a URL or the URL refers to a content that was moved or removed.

I use Nikola to generate my site on github pages and of course I use it to generate my 404.html.

Nikola is really smart and does a lot lot of stuff for you, for example it generates a sitemap.xml that keeps track of all the pages it creates and manages.

The sitemap.xml is used, for example, by search engine to index your website, so you really want to have it in order.

If you let Nikola handle the 404.html page you will have to instruct the software to threat it in a special way, in order to not avoid those lines in your sitemap.xml:


Otherwise the web crawlers will get upset because the http status from github pages will be (like you can guess) 404 Not found!

Fiddling with the ROBOTS_EXCLUSIONS variable as shown at the beginning of the article will just make this work for you.

Final remark about wildcards

Not every robot understands wildcards. So, if your goal is just to exclude the 404.html from the sitemap your are fine with the lines shown at the beginning of the article, otherwise you may want to be more explicit:

ROBOTS_EXCLUSIONS = ["/404.html", "/it/404.html"]

How-to port Plone4 portlets to Plone5

Plone 5 portlets are expected to use z3c.form, while in Plone<=4 portlets have been using formlib.

Given this change you may find error like this:

2014-12-03 14:59:42 ERROR Zope.SiteErrorLog 1417615182.70.607391088835 http://localhost:8080/Plone/++contextportlets++plone.rightcolumn/+/example.portlet
Traceback (innermost last):
  Module ZPublisher.Publish, line 138, in publish
  Module ZPublisher.mapply, line 77, in mapply
  Module ZPublisher.Publish, line 48, in call_object
  Module, line 59, in __call__
  Module z3c.form.form, line 218, in __call__
  Module plone.z3cform.fieldsets.extensible, line 58, in update
  Module plone.autoform.form, line 33, in updateFields
  Module plone.autoform.base, line 54, in updateFieldsFromSchemata
  Module plone.autoform.form, line 22, in schema
NotImplementedError: The class deriving from AutoExtensibleForm must have a 'schema' property

The reason is that the add and edit form classes for the portlets are expected to have an attribute called schema that should be equal to the interface defining the portlet fields. In Plone<=4 that interfaced was used to fill an attribute called form_fields.

Read more…