Views

Add a New View

Configuration

The main configuration of the library is done on the view. By subclassing CRUDView for each new view you can create an individual configuration that turns your model & form into a fully accessible CRUD interface. The available confiugration parameters are described on the class:

class pyramid_crud.views.CRUDView(request)[source]

The base class for all views. Subclassing directly from this gets you a new view configuration for a single model & form. If you specify __abstract__ on it, the class will not be configured at all and you can use it as your own base class.

Note

Configuration is done by Pyramid the moment you call pyramid.config.Configurator.scan() in a way similar to what the pyramid.view.view_config decorator does. If you want to completely disable this behavior, set view_configurator_class to None. Then no route configuration will be done and you have to set up views and routes yourself. This is an advanced technique not recommended for beginners.

The following attributes can be defined to override behavior of the view:

Form
Mandatory argument that specifies the form class for which this view should be created. This must be a form as described in Forms.
url_path

Mandatory arguments if the default view_configurator_class is used. It determines the base path under which this view should be available.

So for example, if this is /myitems then the list view will be reached under the /myitems path whereas the new view will be under /myitems/new.

How and if this parameter is used depends entirely on the implementation of the configurator but it is recommended to keep this parameter for custom implementations as well.

dbsession
Return the current SQLAlchemy session. By default this expects a dbsession attribute on the request object. It is mandatory that you either attach the attribute using an event or override this attribute (you can use a property if you like).
list_display

A tuple if items which should be displayed on the list view. By default a single column of the models __str__ method is used. There are several possibilities of what you might specify here (the options will be tried in this order):

  • A string representing an attribute or callable on the model. If this attribute is callable, it will be called and get no additional arguments (the first argument will already be self, the model instance).

    For example, with a normal field on the model:

    class Model(Base):
         id = Column(Integer, primary_key=True,
                     info={'label': 'ID'})
    
    class View(CRUDView):
         list_display = ('id',)
    

    In this example there will be a single column in the list view. Its title will be “ID” and its value will be the value of the id field in the database.

    Similarly, with a callable:

    class Model(Base):
        id = Column(Integer, primary_key=True)
    
        def id_plus_one(self):
            return self.id + 1
        id_plus_one.info = {'label': 'ID+1'}
    
    class View(CRUDView):
        list_display = ('id_plus_one',)
    
  • A generic callable function. This function will be called with a single argument: The instance of the model. For example:

    class Model(Base):
        id = Column(Integer, primary_key=True)
    
    def id_plus_one(obj):
        return obj.id + 1
    id_plus_one.info  = {'label': 'ID+1'}
    
    class View(CRUDView):
        list_display = (id_plus_one,)
    
  • A string representing a method on the view. This will behave in the same way as for the function callable above except that it must be a string. For example:

    class Model(Base):
        id = Column(Integer, primary_key=True)
    
    class View(CRUDView):
        list_display = ('id_plus_one',)
    
        def id_plus_one(self, obj):
            return obj.id + 1
        id_plus_one.info = {'label': 'ID+1'}
    

Some additional notes on the way this attribute behaves:

  • Some additional configuration is possible on each attribute, regardless of how it is specified. For information on this see The Info Dictionary.
  • A class columnn-<attr-name> is placed on each on each of the <th> fields in the column heading to allow application of CSS attributes, e.g. to set the width of a column.
  • If the attribute info cannot be found on the attribute (at the class level, not instance level), default value is determined as the column heading. If name of the column is __str__ then the name of the model class is fetched. If it is directly callable (in case of a generic callable function), then the name of the function is used. In all other cases the provided string is used. To make for a prettier format, it additionally replaces any underscores by spaces and captializes each word.
actions:
An optional list of action callables or view method names for the dropdown menu. See Adding Actions to Forms for details on how to use it.
theme
A theme is just a collection of template files inside a directory and this is the name of that directory. The recommended way is to use asset specification to unambigously identify the package. By default the bootstrap template is used and so this is set to pyramid_crud:templates/mako/bootstrap. If you want to roll your own theme, you can overwrite this. But if you only want to copy a single template and modify it, you should check out Templates.
template_ext
Which file extension to use for templates. By default, Mako templates are used and so the extension is .mako but any renderer that is recognized by pramid can be used.
template_*

You can specify any name here, e.g. template_list and the CRUDView.get_template_for() method will use this when calling it with list as the action parameter. This is useful for overwriting specific templates but keeping the default behavior for the rest.

Note

The name “ext” for an action is thus not allowed (as template_ext is another configuration). Just don’t define an action with that name.

This way is also impossible for templates in subdirectories, for example fieldsets/horizontal.mako since a slash (“/”) cannot be used on a path. Currently the only way is to overwrite CRUDView.get_template_for().

view_configurator_class
A class that configures all views and routes for this view class. The default implementation is ViewConfigurator which covers basic route & view configuration. However, if you need more advanced functionalities like, for example, permissions, you can change this parameter. See the documentation on ViewConfigurator for details on how to achieve that.

There are also some attributes which you can access. All of them are available on the instance, but only some are also available on the class (in this case, it is noted on the attribute).

routes

A dictionary mapping action names to routes. Action names are such as list or edit and they all have unique route names that can be given to request.route_url. You can use it like this:

url = request.route_url(view.routes["list"])

This will return a URL to the list view.

The routes dictionary is populated by the view_configurator_class.

This can be accessed at the class and instance level.

request
The current request, an instance of pyramid.request.Request.

View & Route Setup

Setting up views and routes is delegated to a special configurator class that creates a route & view for each available view, i.e. list, edit, new and delete. Since you often need to change the routes and views to match your needs, you can subclass this and start overwriting its behavior. The interface is very simple:

Note

There is a slight overhead to configuring views like this because it requires the creation of an additional class. However, approaches like configuring parameters directly on the view are inflexible and setting awkward callables (in theory the most pythonic way) look ugly. Thus, this method is both flexible and easy to read.

class pyramid_crud.views.ViewConfigurator(config, view_class)[source]

The standard implementation of the view configuration. It performs the most basic configuration of routes and views without any extra functionality.

This is sufficient in many cases, but there are several applications where you might want to completely or partially change this behavior. Any time you want to pass additional arguments to pyramid.config.Configurator.add_route() or pyramid.config.Configurator.add_view() you can just subclass this and override the specific methods.

All the public methods must always be implemented according to their documentation or the configuration of views and routes will fail. If you are unsure, you can take a look at the default implementation. It is just a very thin wrapper around the above mentioned methods.

During instantiation the arguments config representing an instance of pyramid.config.Configurator and view_class being your subclassed view class are given to the instance and stored under these values as its attributes.

From the view_class parameter you can access the complete configuration as documented on CRUDView. config should then be used to add routes and views and possibly other configuration you might need.

ViewConfigurator.configure_list_view()[source]

Configure the “list” view by setting its route and view. This method must call add_view to configure the view and add_route to connect a route to it. Afterwards, it must return the name of the configured route that links route and view. This will then be stored in the view’s route dictionary under the “list” key.

def configure_list_view(self):
    self.config.add_view('myview-list',
                         renderer='list.mako',)
    self.config.add_route('myview-list', self.view_class.url_path)
    return 'myview-list'

This does a few things:

  • It sets up the view under the alias myview-list with the template list.mako. Note that the default configuration uses a theme and absolute paths while this configures a template that needs to be in mako.directories.
  • It connects the alias to the configured route via the url_path configuration parameter (the list view is just the base route in this case, but that is totally up to you).
  • It returns this alias from the function so that it can be stored in the routes dictionary on the view.
ViewConfigurator.configure_edit_view()[source]

This method behaves exactly like ViewConfigurator.configure_list_view() except it must configure the edit view, i.e. the view for editing existing objects. It must return the name of the route as well that will then be stored under the “edit” key.

ViewConfigurator.configure_new_view()[source]

This method behaves exactly like ViewConfigurator.configure_list_view() except it must configure the new view, i.e. the view for adding new objects. It must return the name of the route as well that will then be stored under the “new” key.

There are also some helper methods available.

The Info Dictionary

Each object can have an optional info dictionary attached (and in most cases you will want one). The idea is based on the idea of WTForms-Alchemy’s Form Customization and actually just extends it. Several attributes used by this library support inclusion of extra information in this dict. The following options can be set and/or read and some are automatically defined if you do not provide a value. The follwoing values are available:

label
This is taken over from WTForms-Alchemy but is used in more places. Instead of being just used as the label on a form, it is also used as a column heading in the list view. Each object should have one, but some functions set it (for example, the column header function associated with list_display provides a default). For specific behavior on this regarding different views you should consult the associated documentation. While you should normally set it, not setting it will invent some hopefully nice-looking strings for the default usage (basically list and edit views).
description
Used on form fields to describe a field more in-depth than a label can. This text may be arbitrarily long. It is not displayed on all templates (see Fieldset Templates).
css_class
A css class which should be set on this element’s context. Currently this is only used for the list view where the th element gets this class so you can style your table based on individual columns. See the documentation on list_display for more info.
bool
This value is not always set, but when it is set, it indicates if this item is a boolean type. Currently this is only set for the list headings and there it is unused but can be adapted by custom templates.
func
This is only used with actions and defines the callable which executes an action. It is part of the dict returned by _all_actions on the view.

API

The classes, methods and attributes described here are normally not used directly by the user of the library and are just here for the sake of completeness.

CRUDView

The following methods refer to specific views:

CRUDView.list()[source]

List all items for a Model. This is the default view that can be overridden by subclasses to change its behavior.

Returns:A dict with a single key items that is a query which when iterating over yields all items to be listed.
CRUDView.delete(query)[source]

Delete all objects in the query.

CRUDView.edit()[source]

The default view for editing an item. It loads the configured form and model. In edit mode (i.e. with an already existing object) it requires a matchdict mapping primary key names to their values. This has to be ensured during route configuring by setting the correct pattern. The default implementation takes correctly care of this.

Returns:In case of a GET request a dict with the key form denoting the configured form instance with data from an optional model loaded and a key is_new which is a boolean flag indicating whether the actual action is new or edit (allowing for templates to display “New Item” or “Edit Item”).

In case of a POST request, either the same dict is returned or an instance of HTTPFound which indicates success in saving the item to the database.

Raises:ValueError – In case of an invalid, missing or unmatched action. The most likely reason for this is the missing button of a form, e.g. by the name save. By default the following actions are supported: save, save_close, save_new and additionally anything that starts with add_ or delete_ (these two are for internal form handling and inline deletes/adds).

Addtionally, the following helper methods are used internally during several sections of the library:

CRUDView.redirect(route_name=None, *args, **kw)[source]

Convenience function to create a redirect.

Parameters:route_name – The name of the route for which to create a URL. If this is None, the current route is used.

All additional arguments and keyword arguments are passed to pyramid.request.Request.route_url().

Returns:An instance of pyramid.httpexceptions.HTTPFound suitable to be returned from a view to create a redirect.
classmethod CRUDView.get_template_for(action)[source]

Return the name of the template to be used. By default this uses the template in the folder theme with the name action + template_ext, so for example in the default case for a list view: “pyramid_crud:templates/mako/bootstrap/list.mako”.

This method basically just appends the given action to a base path and appends the file extension. As such, it is perfectly fine, to define relative paths here:

view.get_template_for('fieldsets/horizontal')

You can also change single templates by statically defining action_template on the view class where action is replaced by a specific action, e.g. list. So say, for example, you want to only change the default list template and keep the others. In that case, you would specify list_template = "templates/my_crud_list.mako" and the list template would be loaded from there (while still loading all other templates from their default location).

Parameters:action – The action, e.g. list or edit.
CRUDView._get_request_pks()[source]

Get an ordered dictionary of primary key names matching to their value, fetched from the request’s matchdict (not the model!).

Parameters:names – An iterable of names which are to be fetched from the matchdict.
Returns:An OrderedDict of the given names as keys with their corresponding value.
Raises:ValueError – When only some primary keys are set (it is allowed to have all or none of them set)
CRUDView._get_route_pks(obj)[source]

Get a dictionary mapping primary key names to values based on the model (contrary to _get_request_pks() which bases them on the request).

Parameters:obj – An instance of the model.
Returns:A dict with primary key names as keys and their values on the object instance as the values.
CRUDView._edit_route(obj)[source]

Get a route for the edit action based on an objects primary keys.

Parameters:obj – The instance of a model on which the routes values should be based.
Returns:A URL which can be used as the routing URL for redirects or displaying the URL on the page.
CRUDView.iter_head_cols()[source]

Get an iterable of column headings based on the configuration in list_display.

CRUDView.iter_list_cols(obj)[source]

Get an iterable of columns for a given obj suitable as the columns for a single row in the list view. It uses the list_display option to determine the columns.

ViewConfigurator

In addition to the methods described above, the default implementation has a few helper methods. These are not required in any case since they are only called by the above methods. However, since these methods are used to factor out common tedious work, you might either use or override them and possibly not even touch the default implementations above.

ViewConfigurator._configure_view(action, route_action=None, *args, **kw)[source]

Configure a view via pyramid.config.Configurator.add_view() while passing any additional arguments to it.

Parameters:
  • action – The name of the attribute on the view class that represents the action. For example, in the default implementation the list action corresponds to CRUDView.list(). If you rename them, e.g. by naming the list action “_my_list”, this would have to be _my_list regardless of the name of the action.
  • route_action – An optional parameter that is used as the name base for the route. If this is missing, it will take the same value as action. In the default implementation it is used to distinguish between new and edit which use the same action, view and template but different route names.

Overriding this method allows you to change the view configuration for all configured views at once, i.e. you don’t have to change the public methods at all. Just look at their default implementation to see the parameters they use.

ViewConfigurator._configure_route(action, suffix, *args, **kw)[source]

Set up a route via pyramid.config.Configurator.add_route() while passing all addtional arguments through to it.

Parameters:
  • action – The action upon which to base the route name. It must be the same as route_action on _configure_view().
  • suffix – The suffix to be used for the actual path. It is appended to the url_path directly. This may be empty (as is the case for the default list view) but must always be explicitly specified. The result of this will be passed to add_route and so may (and often will) include parameters such as /{id}.

Overriding this method can be done in the same manner as described for _configure_view().

Warning

Some methods on the view require primary keys of the object in question in the matchdict of the request. To guarantee this, the routes have to be correctly set up, i.e. each route that requires this primary key (or keys, depending on the model) has to have a pattern where each primary key name appears once. The default implementation takes care of this via _get_route_pks(), but if you change things you have to ensure this yourself.

Which methods require which values is documented on the respective views of CRUDView.

ViewConfigurator._get_route_name(action)[source]

Get a name for a route of a specific action. The default implementation provides the fully quallyfied name of the view plus the action, e.g. mypackage.views.MyView.list (in this case, the action is “list” for the class “MyView” in the module “mypackage.views”).

Note

In theory this implementation is ambigous, because you could very well have two classes with the same name in the same module. However, this would be a very awkward implementation and is not recommended anyway. If you really choose to do such a thing, you should probably find a better way of naming your routes.

ViewConfigurator._get_route_pks()[source]

Get a string representing all primary keys for a route suitable to be given as suffix to _configure_route(). Some examples will probably best describe the default behavior.

In the case of a model with a single primary key id, the result is the very simple string {id}. If you add this to a route, the primary key of the object will be in the matchdict under the key id.

If you have a model with multiple primary keys, say composite foreign keys, called model1_id and model2_id then the result would be {model1_id},{model2_id}. The order is not important on this one as pyramids routing system will fully take care of it.

Note

If you have some kind of setup where one of the primary keys may contain a comma, this implementation is likely to fail and you have to change it. However, in most cases you will not have a comma and this should be fine.