blog

Photo of Chichen Itza pyramid by Jimmy Baum on Unsplash

A Django-Style Admin Interface For Pyramid

by

Pyramid Logopyramid_formalchemy provides a CRUD interface for Pyramid based on FormAlchemy. Which is to say it looks at your SQLAlchemy models and automagically generates an HTML interface to create, read, update and delete instances of those models from the database, very much like Django’s admin interface. That sounds pretty cool, doesn’t it? In this post I will demonstrate how to get it up and running and then start customizing the forms.

Software screen capture

The Pyramid FAQ suggests you use pyramid_formalchemy if you want a Django style admin interface for Pyramid. I tried it and found that while the documentation is terrible it looks like pyramid_formalchemy could be a good way to do this. It didn’t come out perfectly straight away, and it took some detective work to figure out how to customize it at all, but it looks like it’s actually quite easy to customize in any way you would like.

There’s also fa.bootstrap which looks nice, and I think is based on pyramid_formalchemy, but I didn’t try, and I’m not sure what the license is.

A Quick Introduction

I will create a toy Pyramid app that I can use to keep track of which rock climbing routes I’ve climbed. This will involve first setting up a Pyramid app with sqlalchemy and pyramid_formalchemy, and then creating a sqlalchemy model class to store the info in the database, allowing pyramid_formalchemy to provide the forms to add and edit the information. So following along with the pyramid_formalchemy docs:

Create The App And Get It Up And Running

$ # create the python environment and install necessary packages
$ mkvirtualenv formalchemy
$ pip install six
$ pip install pyramid_formalchemy
$ pip install pyramid_fanstatic
$ pip install fa.jquery

that’s pyramid_fanstatic, not pyramid_fantastic


$ # use Pyramid's pcreate to start a Pyramid app with sqlalchemy scaffolding.
$ pcreate -s alchemy rockclimber

as the docs say, update setup.py to add 'pyramid_formalchemy' to install_requires

$ # now add the pyramid_formalchemy scaffolding
$ python setup.py develop
$ cd ..
$ pcreate -s pyramid_fa rockclimber

as README_FORMALCHEMY.txt says, add config.include('rockclimber.fainit') to rockclimber/init.py:

$ # a missing dependency apparently
$ pip install couchdbkit
$ # run Pyramid's autogenerated db initialization script to create a sqlite db and tables.
$ initialize_rockclimber_db development.ini
$ # run the development web server
$ pserve development.ini

visit localhost:6543/admin

Software screen capture

and woo! that’s pretty fancy! the dummy MyModel class that the alchemy scaffold creates is available to CRUD.

Add My Own Model

So now it’s time for my rock climbing route model.
add to rockclimber/models.py

from sqlalchemy import Boolean, Date
class Route(Base):
    '''
    A SQLAlchemy model class that will persist in the database
    all the information about a rock climbing route that I want
    to keep track of.
    '''
    <strong>tablename</strong> = 'routes'
    id = Column(Integer, primary_key=True)
    name = Column(Text)
    rating = Column(Text)
    guidebook = Column(Text)
    route_type = Column(Text)
    is_indoor = Column(Boolean, default=False)
    location = Column(Text)
    date_climbed = Column(Date)
    climbing_partners = Column(Text)
    is_lead = Column(Boolean, default=True)
    notes = Column(Text)
$ # recreate the database, and restart the web server
$ rm rockclimber.sqlite
$ initialize_rockclimber_db
$ pserve development.ini

Software screen capture

Nice! So that was easy. There are a couple of things wrong with this though, the dates months are weird and it would be nice to have Route Type be a select.

Add A Select Input And A Better Renderer For The Date

One of the files created when the pyramid_fa scaffold was run was called faforms.py. If we make that file look like this:

from formalchemy import forms
from formalchemy import tables
from rockclimber import models
class FieldSet(forms.FieldSet):
    pass
class Grid(tables.Grid):
    pass
route_type_options = [('', ''), ('boulder', 'boulder'), ('sport', 'sport'), ('trad', 'trad')]

Create a specially named instance of FieldSet that pyramid_formalchemy will find and use for the Route model.

Route = FieldSet(models.Route)
Route.configure(
        options=[
            Route.route_type.dropdown(options=route_type_options),
            Route.date_climbed.date(),
            ]
        )

Software screen capture

then we get a dropdown for route and avoid the month problem by using a different renderer for date altogether. There’s still a problem with the dropdown where the current value isn’t selected when you edit the model though.

So there we have it. You should take my solution for the dropdown and date rendering with a grain of salt as I’m not by any means an expert. This did seem to me to be the way you’re supposed to do it because the scaffold creates the faforms.py and then the pyramid_formalchemy views.py does this sort of thing:

350     @actions.action()
351     def new(self):
352         fs = self.get_fieldset(suffix='Add')

and:

 231         def get_fieldset(self, suffix='', id=None):
 232             """return a FieldSet object bound to the correct record for id.
 233             """
 234             request = self.request
 235             model = id and request.model_instance or request.model_class
 236             form_name = request.model_name + suffix
 237             fs = getattr(request.forms, form_name, None)
 238             if fs is None:
 239                 fs = getattr(request.forms, request.model_name,
 240                              self.fieldset_class)

which is to say that on Add it first looks for an instance of a FieldSet named RouteAdd in faforms.py and then, if it fails to find that, for an instance of a FieldSet named Route in the same place, before using a default FieldSet.

Would I Use This For Real?

So, the documentation is bad. I couldn’t find a bunch of tutorials or articles about it when googling for help, and some of the stuff I did find was out of date. The FormAlchemy google group I found had posts mostly between 2007 – 2012 (although more recent posts did have responses) which suggests it’s not currently very actively used. pyramid_formalchemy last got a commit in April 2013. There’s an obvious glaring problem with the out of the box date renderer.

On the other hand pyramid_formalchemy and FormAlchemy seem mature and fully featured. It was quite easy to get up and running and quite easy to customize once I understood what I needed to do. I was able to create a useful app in a couple of hours (even with all the googling) typing very few lines of code. Which is awesome.

I plan on using it again. Have you tried (and perhaps had better success with?) any other packages that solve this problem?

+ more

Accurate Timing

Accurate Timing

In many tasks we need to do something at given intervals of time. The most obvious ways may not give you the best results. Time? Meh. The most basic tasks that don't have what you might call CPU-scale time requirements can be handled with the usual language and...

read more