pyramid_formalchemy provides a CRUD interface for pyramid based on FormAlchemy
It also allows to use FormAlchemy to render forms in your application.
pyramid_formalchemy must be a dependency of you application, so you must add “pyramid_formalchemy” as a dependency in your setup.py under install_requires. You must now update your environment, in case of buildout, by running a new buildout. If you want nicer jquery functionality also add a dependency for fa.jquery.
pyramid_formalchemy also provides a pyramid scaffold. It can be used to add a skeleton to an existing project or to create a new project. If you create a new project, you must first install pyramid_formalchemy in your python environment, either with pip:
$ pip install pyramid_formalchemy pyramid_fanstatic fa.jquery
or with easy_install:
$ easy_install pyramid_formalchemy pyramid_fanstatic fa.jquery
Only after that, the pyramid scaffold becomes available. The template was made with the idea that it can be used to extend existing applications. It does not create an app for you. For bootstrapping your app, you need another pyramid scaffold. The provided template works well with alchemy, Akhet. To bootstrap an application, call paster like that:
$ pcreate -s alchemy -s pyramid_fa myapp
Or for Akhet:
$ pcreate -s akhet -s pyramid_fa myapp
The application is created by akhet, akhet does not know about pyramid_formalchemy, and pyramid_formalchemy cannot modify the app configuration. So you have to do this by hand. First, you must add the install dependency like explained earlier. Second, you must add the following line in the main method that returns the wsgi app, directly after Configurator has been created (The example assumes that the Configurator instance is stored under the name “config”):
...
config.include('myapp.fainit')
...
More details are explained in myapp/README_FORMALCHEMY.txt. The process is the same for other templates. For the pyramid ones there are additional changes necessary that are also explained in fareadme.txt
To add the minimum configuration to an existing application, you should be able to run:
$ pcreate -s pyramid_fa myapp
All files that paster creates are prefixed with fa, and should not interfere with existing code. The other customizations described for fresh applications are also valid for existing apps.
Add an empty forms.py module at the root of your project.
Now you just need to include two lines of configuration in the __init__.main() function of your project. Here is the one used for testing:
from pyramid.config import Configurator
from sqlalchemy import engine_from_config
from pyramidapp.models import initialize_sql
from pyramidapp import events; events #pyflakes
def main(global_config, **settings):
""" This function returns a Pyramid WSGI application.
"""
engine = engine_from_config(settings, 'sqlalchemy.')
initialize_sql(engine)
config = Configurator(settings=settings)
config.add_static_view('static', 'pyramidapp:static')
config.add_route('home', '/')
config.add_view('pyramidapp.views.my_view',
route_name='home',
renderer='templates/mytemplate.pt')
# pyramid_formalchemy's configuration
config.include('pyramid_formalchemy')
# register an admin UI
config.formalchemy_admin('admin', package='pyramidapp')
# register an admin UI for a single model
config.formalchemy_model('foo', package='pyramidapp', model='pyramidapp.models.Foo')
# register custom model listing
config.formalchemy_model_view('admin',
model='pyramidapp.models.Foo',
context='pyramid_formalchemy.resources.ModelListing',
renderer='templates/foolisting.pt',
attr='listing',
request_method='GET',
permission='view')
# register custom model view
config.formalchemy_model_view('admin',
model='pyramidapp.models.Foo',
context='pyramid_formalchemy.resources.Model',
name='',
renderer='templates/fooshow.pt',
attr='show',
request_method='GET',
permission='view')
return config.make_wsgi_app()
This will render the basic formalchemy interface.
It’s better to enable the jquery features like this:
def main(global_config, **settings):
""" This function returns a Pyramid WSGI application.
"""
engine = engine_from_config(settings, 'sqlalchemy.')
initialize_sql(engine)
config = Configurator(settings=settings)
config.add_static_view('static', 'pyramidapp:static')
config.add_route('home', '/')
config.add_view('pyramidapp.views.my_view',
route_name='home',
renderer='templates/mytemplate.pt')
# pyramid_formalchemy's configuration
config.include('pyramid_formalchemy')
config.include('fa.jquery')
# register an admin UI
config.formalchemy_admin('/admin', package='pyramidapp', view='fa.jquery.pyramid.ModelView')
# register an admin UI for a single model
config.formalchemy_model('/foo', package='pyramidapp',
view='fa.jquery.pyramid.ModelView',
model='pyramidapp.models.Foo')
return config.make_wsgi_app()
That’s it. Now launch your app, browse /admin/ and enjoy it !
Here is a typical model to use full features of pyramid_formalchemy. Notice that the fields are defined using formalchemy.Column():
class User(Base):
__label__ = _('User') # label used in UI
__plural__ = _('Users') # plural used in UI
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(Unicode, nullable=False, label=_('Name')) # label is used in forms
# the renderer argument will be used for the group relation. You can use a
# backref_renderer option to set the renderer of the users relation
group_id = Column(Integer, ForeignKey('groups.id'),
renderer=renderers.autocomplete_relation(filter_by='name'))
group = relation("Group", uselist=False, backref='users')
def __unicode__(self):
return self.name
See also pyramid_formalchemy.actions to customize form buttons per model.
In the toward examples we just pass a package parameter to configure(). By default the function will try to load package.models, package.models.DBSession and package.forms but you can override this. In this case you don’t need to specify a package:
config.formalchemy_admin(config,
forms='formalchemy_project.forms',
models='formalchemy_project.mymodels',
session_factory='formalchemy_project.session.Session',
)
You can also change the path prefix used. pyramid_formalchemy will use /admin/ by default. See configure().
def main(global_config, **settings):
""" This function returns a Pyramid WSGI application.
"""
engine = engine_from_config(settings, 'sqlalchemy.')
models.initialize_sql(engine)
config = Configurator(settings=settings)
config.include('pyramid_tm')
config.add_translation_dirs('formalchemy_project:locale/')
# pyramid_formalchemy's configuration
config.include('pyramid_formalchemy')
config.include('fa.jquery')
config.include('fa.extjs')
# Admin UI (Used for the demo. Not really useful here...)
config.formalchemy_admin('/extjs', package='formalchemy_project', view='fa.extjs.ModelView')
config.formalchemy_admin('/admin', package='formalchemy_project', view='fa.jquery.pyramid.ModelView')
# Article admin UI. Use a custom query_factory to filter by user
# Here is the interesting part
def query_factory(request, query, id=None):
"""this query factory use request.matchdict to retrieve user's
articles. Of course, you can do anything like check that the user found
in matchdict is the REMOTE_USER"""
user = request.session_factory.query(models.User).filter_by(name=request.matchdict['user']).one()
if id:
return query.filter_by(user=user, id=id).one()
else:
return query.filter_by(user=user)
config.formalchemy_model('/articles/{user}', package='formalchemy_project',
model='formalchemy_project.models.Article',
query_factory=query_factory,
view='fa.jquery.pyramid.ModelView')
return config.make_wsgi_app()
You can also register custom CRUD views per ModelListing:
config.formalchemy_model_view('admin',
model='pyramidapp.models.Foo',
context='pyramid_formalchemy.resources.ModelListing',
renderer='templates/foolisting.pt',
attr='listing',
request_method='GET',
permission='view')
and per Model:
config.formalchemy_model_view('admin',
model='pyramidapp.models.Foo',
context='pyramid_formalchemy.resources.Model',
name='',
renderer='templates/fooshow.pt',
attr='show',
request_method='GET',
permission='view')
pyramid_formalchemy got some hooks to help you to customize things. See pyramid_formalchemy.events.
pyramid_formalchemy allow you to customize links and actions of your views. See pyramid_formalchemy.actions.
pyramid_formalchemy takes care of some __acl__ attributes.
You just need to subclass the default factory in your application:
from pyramid.config import Configurator
from sqlalchemy import engine_from_config
from pyramid.authorization import ACLAuthorizationPolicy
from pyramid.authentication import RemoteUserAuthenticationPolicy
from pyramid_formalchemy.resources import Models
from pyramid.security import Allow, Authenticated, ALL_PERMISSIONS
from pyramidapp.models import initialize_sql
class ModelsWithACL(Models):
"""A factory to override the default security setting"""
__acl__ = [
(Allow, 'admin', ALL_PERMISSIONS),
(Allow, Authenticated, 'view'),
(Allow, 'editor', 'edit'),
(Allow, 'manager', ('new', 'edit', 'delete')),
]
def main(global_config, **settings):
""" This function returns a Pyramid WSGI application.
"""
engine = engine_from_config(settings, 'sqlalchemy.')
initialize_sql(engine)
# configure the security stuff
config = Configurator(settings=settings,
authentication_policy=RemoteUserAuthenticationPolicy(),
authorization_policy=ACLAuthorizationPolicy())
config.add_static_view('static', 'pyramidapp:static')
config.add_route('home', '/')
config.add_view('pyramidapp.views.my_view',
route_name='home',
renderer='templates/mytemplate.pt')
# pyramid_formalchemy's configuration
config.include('pyramid_formalchemy')
config.formalchemy_admin('admin', package='pyramidapp',
factory=ModelsWithACL) # use the secure factory
return config.make_wsgi_app()
You can also add an __acl__ attribute to your model class:
class Bar(Base):
__tablename__ = 'bar'
__acl__ = [
(Allow, 'admin', ALL_PERMISSIONS),
(Allow, 'bar_manager', ('view', 'new', 'edit')),
]
id = Column(Integer, primary_key=True)
foo = Column(Unicode(255))