wuttaweb.views.master
¶
Base Logic for Master Views
- class wuttaweb.views.master.MasterView(request, context=None)[source]¶
Base class for “master” views.
Master views typically map to a table in a DB, though not always. They essentially are a set of CRUD views for a certain type of data record.
Many attributes may be overridden in subclass. For instance to define
model_class
:from wuttaweb.views import MasterView from wuttjamaican.db.model import Person class MyPersonView(MasterView): model_class = Person def includeme(config): MyPersonView.defaults(config)
Note
Many of these attributes will only exist if they have been explicitly defined in a subclass. There are corresponding
get_xxx()
methods which should be used instead of accessing these attributes directly.- model_class¶
Optional reference to a data model class. While not strictly required, most views will set this to a SQLAlchemy mapped class, e.g.
Person
.Code should not access this directly but instead call
get_model_class()
.
- model_name¶
Optional override for the view’s data model name, e.g.
'WuttaWidget'
.Code should not access this directly but instead call
get_model_name()
.
- model_name_normalized¶
Optional override for the view’s “normalized” data model name, e.g.
'wutta_widget'
.Code should not access this directly but instead call
get_model_name_normalized()
.
- model_title¶
Optional override for the view’s “humanized” (singular) model title, e.g.
"Wutta Widget"
.Code should not access this directly but instead call
get_model_title()
.
- model_title_plural¶
Optional override for the view’s “humanized” (plural) model title, e.g.
"Wutta Widgets"
.Code should not access this directly but instead call
get_model_title_plural()
.
- model_key¶
Optional override for the view’s “model key” - e.g.
'id'
(string for simple case) or composite key such as('id_field', 'name_field')
.If
model_class
is set to a SQLAlchemy mapped class, the model key can be determined automatically.Code should not access this directly but instead call
get_model_key()
.
- grid_key¶
Optional override for the view’s grid key, e.g.
'widgets'
.Code should not access this directly but instead call
get_grid_key()
.
- config_title¶
Optional override for the view’s “config” title, e.g.
"Wutta Widgets"
(to be displayed as Configure Wutta Widgets).Code should not access this directly but instead call
get_config_title()
.
- route_prefix¶
Optional override for the view’s route prefix, e.g.
'wutta_widgets'
.Code should not access this directly but instead call
get_route_prefix()
.
- permission_prefix¶
Optional override for the view’s permission prefix, e.g.
'wutta_widgets'
.Code should not access this directly but instead call
get_permission_prefix()
.
- url_prefix¶
Optional override for the view’s URL prefix, e.g.
'/widgets'
.Code should not access this directly but instead call
get_url_prefix()
.
- template_prefix¶
Optional override for the view’s template prefix, e.g.
'/widgets'
.Code should not access this directly but instead call
get_template_prefix()
.
- listable¶
Boolean indicating whether the view model supports “listing” - i.e. it should have an
index()
view. Default value isTrue
.
- grid_columns¶
List of columns for the
index()
view grid.This is optional; see also
get_grid_columns()
.
- grid_row_class(obj, data, i)¶
This method is not defined on the
MasterView
base class; however if a subclass defines it then it will be automatically used to providerow_class
for the mainindex()
grid.For more info see
get_row_class()
.
- filterable¶
Boolean indicating whether the grid for the
index()
view should allow filtering of data. Default isTrue
.This is used by
make_model_grid()
to set the grid’sfilterable
flag.
- filter_defaults¶
Optional dict of default filter state.
This is used by
make_model_grid()
to set the grid’sfilter_defaults
.Only relevant if
filterable
is true.
- sortable¶
Boolean indicating whether the grid for the
index()
view should allow sorting of data. Default isTrue
.This is used by
make_model_grid()
to set the grid’ssortable
flag.See also
sort_on_backend
andsort_defaults
.
- sort_on_backend¶
Boolean indicating whether the grid data for the
index()
view should be sorted on the backend. Default isTrue
.This is used by
make_model_grid()
to set the grid’ssort_on_backend
flag.Only relevant if
sortable
is true.
- sort_defaults¶
Optional list of default sorting info. Applicable for both frontend and backend sorting.
This is used by
make_model_grid()
to set the grid’ssort_defaults
.Only relevant if
sortable
is true.
- paginated¶
Boolean indicating whether the grid data for the
index()
view should be paginated. Default isTrue
.This is used by
make_model_grid()
to set the grid’spaginated
flag.
- paginate_on_backend¶
Boolean indicating whether the grid data for the
index()
view should be paginated on the backend. Default isTrue
.This is used by
make_model_grid()
to set the grid’spaginate_on_backend
flag.
- creatable¶
Boolean indicating whether the view model supports “creating” - i.e. it should have a
create()
view. Default value isTrue
.
- viewable¶
Boolean indicating whether the view model supports “viewing” - i.e. it should have a
view()
view. Default value isTrue
.
- editable¶
Boolean indicating whether the view model supports “editing” - i.e. it should have an
edit()
view. Default value isTrue
.See also
is_editable()
.
- deletable¶
Boolean indicating whether the view model supports “deleting” - i.e. it should have a
delete()
view. Default value isTrue
.See also
is_deletable()
.
- deletable_bulk¶
Boolean indicating whether the view model supports “bulk deleting” - i.e. it should have a
delete_bulk()
view. Default value isFalse
.See also
deletable_bulk_quick
.
- deletable_bulk_quick¶
Boolean indicating whether the view model supports “quick” bulk deleting, i.e. the operation is reliably quick enough that it should happen synchronously with no progress indicator.
Default is
False
in which case a progress indicator is shown while the bulk deletion is performed.Only relevant if
deletable_bulk
is true.
- form_fields¶
List of fields for the model form.
This is optional; see also
get_form_fields()
.
- has_autocomplete¶
Boolean indicating whether the view model supports “autocomplete” - i.e. it should have an
autocomplete()
view. Default isFalse
.
- downloadable¶
Boolean indicating whether the view model supports “downloading” - i.e. it should have a
download()
view. Default isFalse
.
- executable¶
Boolean indicating whether the view model supports “executing” - i.e. it should have an
execute()
view. Default isFalse
.
- configurable¶
Boolean indicating whether the master view supports “configuring” - i.e. it should have a
configure()
view. Default value isFalse
.
- autocomplete()[source]¶
View which accepts a single
term
param, and returns a JSON list of autocomplete results to match.By default, this view is included only if
has_autocomplete
is true. It usually maps to a URL like/widgets/autocomplete
.Subclass generally does not need to override this method, but rather should override the others which this calls:
- autocomplete_data(term)[source]¶
Should return the data/query for the “matching” model records, based on autocomplete search term. This is called by
autocomplete()
.Subclass must override this; default logic returns no data.
- Parameters:
term – String search term as-is from user, e.g. “foo bar”.
- Returns:
List of data records, or SQLAlchemy query.
- autocomplete_normalize(obj)[source]¶
Should return a “normalized” version of the given model record, suitable for autocomplete JSON results. This is called by
autocomplete()
.Subclass may need to override this; default logic is simplistic but will work for basic models. It returns the “autocomplete results” dict for the object:
{ 'value': obj.uuid, 'label': str(obj), }
The 2 keys shown are required; any other keys will be ignored by the view logic but may be useful on the frontend widget.
- Parameters:
obj – Model record/instance.
- Returns:
Dict of “autocomplete results” format, as shown above.
- collect_labels()[source]¶
Collect all labels defined by the view class and/or its parents.
A master view can declare labels via class-level attribute, like so:
from wuttaweb.views import MasterView class WidgetView(MasterView): labels = { 'id': "Widget ID", 'serial_no': "Serial Number", }
All such labels, defined by any class from which the master view inherits, will be returned. However if the same label key is defined by multiple classes, the “subclass” always wins.
Labels defined in this way will apply to both forms and grids. See also
set_labels()
.- Returns:
Dict of all labels found.
- configure(session=None)[source]¶
View for configuring aspects of the app which are pertinent to this master view and/or model.
By default, this view is included only if
configurable
is true. It usually maps to a URL like/widgets/configure
.The expected workflow is as follows:
user navigates to Configure page
user modifies settings and clicks Save
this view then deletes all “known” settings
then it saves user-submitted settings
That is unless
remove_settings
is requested, in which case settings are deleted but then none are saved. The “known” settings by default include only the “simple” settings.As a general rule, a particular setting should be configurable by (at most) one master view. Some settings may never be exposed at all. But when exposing a setting, careful thought should be given to where it logically/best belongs.
Some settings are “simple” and a master view subclass need only provide their basic definitions via
configure_get_simple_settings()
. If complex settings are needed, subclass must override one or more other methods to achieve the aim(s).See also related methods, used by this one:
- configure_form(form)[source]¶
Configure the given model form, as needed.
This is called by
make_model_form()
- for multiple CRUD views (create, view, edit, delete, possibly others).The default logic here does just one thing: when “editing” (i.e. in
edit()
view) then all fields which are part of themodel_key
will be marked viaset_readonly()
so the user cannot change primary key values for a record.Subclass may override as needed. The
form
param will already be “complete” and ready to use as-is, but this method can further modify it based on request details etc.
- configure_gather_settings(data, simple_settings=None)[source]¶
Collect the full set of “normalized” settings from user request, so that
configure()
can save them.Settings are gathered from the given request (e.g. POST)
data
, but also taking into account what we know based on the simple setting definitions.Subclass may need to override this method if complex settings are required.
- Parameters:
data – Form data submitted via POST request.
simple_settings – Optional list of simple settings, if already initialized. Otherwise it is retrieved via
configure_get_simple_settings()
.
This method must return a list of normalized settings, similar in spirit to the definition syntax used in
configure_get_simple_settings()
. However the format returned here is minimal and contains just name/value:{ 'name': 'wutta.app_title', 'value': 'Wutta Wutta', }
Note that the
value
will always be a string.Also note, whereas it’s possible
data
will not contain all known settings, the return value should (potentially) contain all of them.The one exception is when a simple setting has null value, by default it will not be included in the result (hence, not saved to DB) unless the setting definition has the
save_if_empty
flag set.
- configure_get_context(simple_settings=None)[source]¶
Returns the full context dict, for rendering the
configure()
page template.Default context will include
simple_settings
(normalized to just name/value).You may need to override this method, to add additional “complex” settings etc.
- Parameters:
simple_settings – Optional list of simple settings, if already initialized. Otherwise it is retrieved via
configure_get_simple_settings()
.- Returns:
Context dict for the page template.
- configure_get_simple_settings()[source]¶
This should return a list of “simple” setting definitions for the
configure()
view, which can be handled in a more automatic way. (This is as opposed to some settings which are more complex and must be handled manually; those should not be part of this method’s return value.)Basically a “simple” setting is one which can be represented by a single field/widget on the Configure page.
The setting definitions returned must each be a dict of “attributes” for the setting. For instance a very simple setting might be:
{'name': 'wutta.app_title'}
The
name
is required, everything else is optional. Here is a more complete example:{ 'name': 'wutta.production', 'type': bool, 'default': False, 'save_if_empty': False, }
Note that if specified, the
default
should be of the same data type as defined for the setting (bool
in the above example). The defaulttype
isstr
.Normally if a setting’s value is effectively null, the setting is removed instead of keeping it in the DB. This behavior can be changed per-setting via the
save_if_empty
flag.- Returns:
List of setting definition dicts as described above. Note that their order does not matter since the template must explicitly define field layout etc.
- configure_grid(grid)[source]¶
Configure the grid for the
index()
view.This is called by
make_model_grid()
.There is no default logic here; subclass should override as needed. The
grid
param will already be “complete” and ready to use as-is, but this method can further modify it based on request details etc.
- configure_remove_settings(simple_settings=None, session=None)[source]¶
Remove all “known” settings from the DB; this is called by
configure()
.The point of this method is to ensure all “known” settings which are managed by this master view, are purged from the DB.
The default logic can handle this automatically for simple settings; subclass must override for any complex settings.
- Parameters:
simple_settings – Optional list of simple settings, if already initialized. Otherwise it is retrieved via
configure_get_simple_settings()
.
- configure_save_settings(settings, session=None)[source]¶
Save the given settings to the DB; this is called by
configure()
.This method expects a list of name/value dicts and will simply save each to the DB, with no “conversion” logic.
- Parameters:
settings – List of normalized setting definitions, as returned by
configure_gather_settings()
.
- create()[source]¶
View to “create” a new model record.
This usually corresponds to a URL like
/widgets/new
.By default, this view is included only if
creatable
is true.The default “create” view logic will show a form with field widgets, allowing user to submit new values which are then persisted to the DB (assuming typical SQLAlchemy model).
Subclass normally should not override this method, but rather one of the related methods which are called (in)directly by this one:
- create_save_form(form)[source]¶
This method is responsible for “converting” the validated form data to a model instance, and then “saving” the result, e.g. to DB. It is called by
create()
.Subclass may override this, or any of the related methods called by this one:
- Returns:
Should return the resulting model instance, e.g. as produced by
objectify()
.
- classmethod defaults(config)[source]¶
Provide default Pyramid configuration for a master view.
This is generally called from within the module’s
includeme()
function, e.g.:from wuttaweb.views import MasterView class WidgetView(MasterView): model_name = 'Widget' def includeme(config): WidgetView.defaults(config)
- Parameters:
config – Reference to the app’s
pyramid.config.Configurator
instance.
- delete()[source]¶
View to delete an existing model instance.
This usually corresponds to a URL like
/widgets/XXX/delete
whereXXX
represents the key/ID for the record.By default, this view is included only if
deletable
is true.The default “delete” view logic will show a “psuedo-readonly” form with no fields editable, but with a submit button so user must confirm, before deletion actually occurs.
Subclass normally should not override this method, but rather one of the related methods which are called (in)directly by this one:
- delete_bulk()[source]¶
View to delete all records in the current
index()
grid data set, i.e. those matching current query.This usually corresponds to a URL like
/widgets/delete-bulk
.By default, this view is included only if
deletable_bulk
is true.This view requires POST method. When it is finished deleting, user is redirected back to
index()
view.Subclass normally should not override this method, but rather one of the related methods which are called (in)directly by this one:
- delete_bulk_action(data, progress=None)[source]¶
This method performs the actual bulk deletion, for the given data set. This is called via
delete_bulk()
.Default logic will call
is_deletable()
for every data record, and if that returns true then it callsdelete_instance()
. A progress indicator will be updated if one is provided.Subclass should override if needed.
- delete_instance(obj)[source]¶
Delete the given model instance.
As of yet there is no default logic for this method; it will raise
NotImplementedError
. Subclass should override if needed.This method is called by
delete_save_form()
.
- delete_save_form(form)[source]¶
Perform the delete operation(s) based on the given form data.
Default logic simply calls
delete_instance()
on the form’smodel_instance
.This method is called by
delete()
after it has validated the form.
- download()[source]¶
View to download a file associated with a model record.
This usually corresponds to a URL like
/widgets/XXX/download
whereXXX
represents the key/ID for the record.By default, this view is included only if
downloadable
is true.This method will (try to) locate the file on disk, and return it as a file download response to the client.
The GET request for this view may contain a
filename
query string parameter, which can be used to locate one of various files associated with the model record. This filename is passed todownload_path()
for locating the file.For instance:
/widgets/XXX/download?filename=widget-specs.txt
Subclass normally should not override this method, but rather one of the related methods which are called (in)directly by this one:
- download_path(obj, filename)[source]¶
Should return absolute path on disk, for the given object and filename. Result will be used to return a file response to client. This is called by
download()
.Default logic always returns
None
; subclass must override.- Parameters:
obj – Refefence to the model instance.
filename – Name of file for which to retrieve the path.
- Returns:
Path to file, or
None
if not found.
Note that
filename
may beNone
in which case the “default” file path should be returned, if applicable.If this method returns
None
(as it does by default) then thedownload()
view will return a 404 not found response.
- edit()[source]¶
View to “edit” details of an existing model record.
This usually corresponds to a URL like
/widgets/XXX/edit
whereXXX
represents the key/ID for the record.By default, this view is included only if
editable
is true.The default “edit” view logic will show a form with field widgets, allowing user to modify and submit new values which are then persisted to the DB (assuming typical SQLAlchemy model).
Subclass normally should not override this method, but rather one of the related methods which are called (in)directly by this one:
- edit_save_form(form)[source]¶
This method is responsible for “converting” the validated form data to a model instance, and then “saving” the result, e.g. to DB. It is called by
edit()
.Subclass may override this, or any of the related methods called by this one:
- Returns:
Should return the resulting model instance, e.g. as produced by
objectify()
.
- execute()[source]¶
View to “execute” a model record. Requires a POST request.
This usually corresponds to a URL like
/widgets/XXX/execute
whereXXX
represents the key/ID for the record.By default, this view is included only if
executable
is true.Probably this is a “rare” view to implement for a model. But there are two notable use cases so far, namely:
upgrades (cf.
UpgradeView
)batches (not yet implemented; cf. Data Batch Processing in Rattail Manual)
The general idea is to take some “irrevocable” action associated with the model record. In the case of upgrades, it is to run the upgrade script. For batches it is to “push live” the data held within the batch.
Subclass normally should not override this method, but rather one of the related methods which are called (in)directly by this one:
- execute_instance(obj, user, progress=None)[source]¶
Perform the actual “execution” logic for a model record. Called by
execute()
.This method does nothing by default; subclass must override.
- Parameters:
obj – Reference to the model instance.
user – Reference to the
User
who is doing the execute.progress – Optional progress indicator factory.
- get_action_url(action, obj, **kwargs)[source]¶
Generate an “action” URL for the given model instance.
This is a shortcut which generates a route name based on
get_route_prefix()
and theaction
param.It returns the URL based on generated route name and object’s model key values.
- Parameters:
action – String name for the action, which corresponds to part of some named route, e.g.
'view'
or'edit'
.obj – Model instance object.
- get_action_url_delete(obj, i)[source]¶
Returns the “delete” grid action URL for the given object, if applicable.
Most typically this is like
/widgets/XXX/delete
whereXXX
represents the object’s key/ID.This first calls
is_deletable()
and if that is false, this method will returnNone
.Calls
get_action_url()
to generate the true URL.
- get_action_url_edit(obj, i)[source]¶
Returns the “edit” grid action URL for the given object, if applicable.
Most typically this is like
/widgets/XXX/edit
whereXXX
represents the object’s key/ID.This first calls
is_editable()
and if that is false, this method will returnNone
.Calls
get_action_url()
to generate the true URL.
- get_action_url_view(obj, i)[source]¶
Returns the “view” grid action URL for the given object.
Most typically this is like
/widgets/XXX
whereXXX
represents the object’s key/ID.Calls
get_action_url()
under the hood.
- get_class_hierarchy(topfirst=True)[source]¶
Convenience to return a list of classes from which the current class inherits.
This is a wrapper around
wuttjamaican.util.get_class_hierarchy()
.
- classmethod get_config_title()[source]¶
Returns the “config title” for the view/model.
The config title is used for page title in the
configure()
view, as well as links to it. It is usually plural, e.g."Wutta Widgets"
in which case that winds up being displayed in the web app as: Configure Wutta WidgetsThe default logic will call
get_model_title_plural()
and return that as-is. A subclass may override by assigningconfig_title
.
- get_fallback_templates(template)[source]¶
Returns a list of “fallback” template paths which may be attempted for rendering a view. This is used within
render_to_response()
if the “first guess” template file was not found.- Parameters:
template – Base name for a template (without prefix), e.g.
'custom'
.- Returns:
List of full template paths to be tried, based on the specified template. For instance if
template
is'custom'
this will (by default) return:['/master/custom.mako']
- get_form_fields()[source]¶
Returns the initial list of field names for the model form.
This is called by
make_model_form()
; in the resultingForm
instance, this becomesfields
.This method may return
None
, in which case the form may (try to) generate its own default list.Subclass may define
form_fields
for simple cases, or can override this method if needed.Note that
configure_form()
may be used to further modify the final field list, regardless of what this method returns. So a common pattern is to declare all “supported” fields by settingform_fields
but then optionally remove or replace some inconfigure_form()
.
- get_grid_columns()[source]¶
Returns the default list of grid column names, for the
index()
view.This is called by
make_model_grid()
; in the resultingGrid
instance, this becomescolumns
.This method may return
None
, in which case the grid may (try to) generate its own default list.Subclass may define
grid_columns
for simple cases, or can override this method if needed.Also note that
configure_grid()
may be used to further modify the final column set, regardless of what this method returns. So a common pattern is to declare all “supported” columns by settinggrid_columns
but then optionally remove or replace some of those withinconfigure_grid()
.
- get_grid_data(columns=None, session=None)[source]¶
Returns the grid data for the
index()
view.This is called by
make_model_grid()
; in the resultingGrid
instance, this becomesdata
.Default logic will call
get_query()
and if successful, return the list fromquery.all()
. Otherwise returns an empty list. Subclass should override as needed.
- classmethod get_grid_key()[source]¶
Returns the (presumably) unique key to be used for the primary grid in the
index()
view. This key may also be used as the basis (key prefix) for secondary grids.This is called from
make_model_grid()
; in the resultingGrid
instance, this becomeskey
.The default logic for this method will call
get_route_prefix()
and return that value as-is. A subclass may override by assigninggrid_key
.
- get_index_title()[source]¶
Returns the main index title for the master view.
By default this returns the value from
get_model_title_plural()
. Subclass may override as needed.
- get_index_url(**kwargs)[source]¶
Returns the URL for master’s
index()
view.NB. this returns
None
iflistable
is false.
- get_instance(session=None, matchdict=None)[source]¶
This should return the appropriate model instance, based on the
matchdict
of model keys.Normally this is called with no arguments, in which case the
pyramid.request.Request.matchdict
is used, and will return the “current” model instance based on the request (route/params).If a
matchdict
is provided then that is used instead, to obtain the model keys. In the simple/common example of a “native” model in WuttaWeb, this would look like:keys = {'uuid': '38905440630d11ef9228743af49773a4'} obj = self.get_instance(matchdict=keys)
Although some models may have different, possibly composite key names to use instead. The specific keys this logic is expecting are the same as returned by
get_model_key()
.If this method is unable to locate the instance, it should raise a 404 error, i.e.
notfound()
.Default implementation of this method should work okay for views which define a
model_class
. For other views however it will raiseNotImplementedError
, so subclass may need to define.Warning
If you are defining this method for a subclass, please note this point regarding the 404 “not found” logic.
It is not enough to simply return this 404 response, you must explicitly raise the error. For instance:
def get_instance(self, **kwargs): # ..try to locate instance.. obj = self.locate_instance_somehow() if not obj: # NB. THIS MAY NOT WORK AS EXPECTED #return self.notfound() # nb. should always do this in get_instance() raise self.notfound()
This lets calling code not have to worry about whether or not this method might return
None
. It can safely assume it will get back a model instance, or else a 404 will kick in and control flow goes elsewhere.
- get_instance_title(instance)[source]¶
Return the human-friendly “title” for the instance, to be used in the page title when viewing etc.
Default logic returns the value from
str(instance)
; subclass may override if needed.
- classmethod get_instance_url_prefix()[source]¶
Generate the URL prefix specific to an instance for this model view. This will include model key param placeholders; it winds up looking like:
/widgets/{uuid}
/resources/{foo}|{bar}|{baz}
The former being the most simple/common, and the latter showing what a “composite” model key looks like, with pipe symbols separating the key parts.
- classmethod get_model_class()[source]¶
Returns the model class for the view (if defined).
A model class will usually be a SQLAlchemy mapped class, e.g.
Person
.There is no default value here, but a subclass may override by assigning
model_class
.Note that the model class is not required - however if you do not set the
model_class
, then you must set themodel_name
.
- classmethod get_model_key()[source]¶
Returns the “model key” for the master view.
This should return a tuple containing one or more “field names” corresponding to the primary key for data records.
In the most simple/common scenario, where the master view represents a Wutta-based SQLAlchemy model, the return value for this method is:
('uuid',)
But there is no “sane” default for other scenarios, in which case subclass should define
model_key
. If the model key cannot be determined, raisesAttributeError
.- Returns:
Tuple of field names comprising the model key.
- classmethod get_model_name()[source]¶
Returns the model name for the view.
A model name should generally be in the format of a Python class name, e.g.
'WuttaWidget'
. (Note this is singular, not plural.)The default logic will call
get_model_class()
and return that class name as-is. A subclass may override by assigningmodel_name
.
- classmethod get_model_name_normalized()[source]¶
Returns the “normalized” model name for the view.
A normalized model name should generally be in the format of a Python variable name, e.g.
'wutta_widget'
. (Note this is singular, not plural.)The default logic will call
get_model_name()
and simply lower-case the result. A subclass may override by assigningmodel_name_normalized
.
- classmethod get_model_title()[source]¶
Returns the “humanized” (singular) model title for the view.
The model title will be displayed to the user, so should have proper grammar and capitalization, e.g.
"Wutta Widget"
. (Note this is singular, not plural.)The default logic will call
get_model_name()
and use the result as-is. A subclass may override by assigningmodel_title
.
- classmethod get_model_title_plural()[source]¶
Returns the “humanized” (plural) model title for the view.
The model title will be displayed to the user, so should have proper grammar and capitalization, e.g.
"Wutta Widgets"
. (Note this is plural, not singular.)The default logic will call
get_model_title()
and simply add a's'
to the end. A subclass may override by assigningmodel_title_plural
.
- classmethod get_permission_prefix()[source]¶
Returns the “permission prefix” for the master view. This prefix is used for all permissions defined by the view class.
For instance if permission prefix is
'widgets'
then a view might have these permissions:'widgets.list'
'widgets.create'
'widgets.edit'
'widgets.delete'
The default logic will call
get_route_prefix()
and use that value as-is. A subclass may override by assigningpermission_prefix
.
- get_query(session=None)[source]¶
Returns the main SQLAlchemy query object for the
index()
view. This is called byget_grid_data()
.Default logic for this method returns a “plain” query on the
model_class
if that is defined; otherwiseNone
.
- classmethod get_route_prefix()[source]¶
Returns the “route prefix” for the master view. This prefix is used for all named routes defined by the view class.
For instance if route prefix is
'widgets'
then a view might have these routes:'widgets'
'widgets.create'
'widgets.edit'
'widgets.delete'
The default logic will call
get_model_name_normalized()
and simply add an's'
to the end, making it plural. A subclass may override by assigningroute_prefix
.
- classmethod get_template_prefix()[source]¶
Returns the “template prefix” for the master view. This prefix is used to guess which template path to render for a given view.
Using the same example as in
get_url_prefix()
, the template prefix would also be'/widgets'
and the templates assumed for those routes would be:/widgets/index.mako
/widgets/create.mako
/widgets/edit.mako
/widgets/delete.mako
The default logic will call
get_url_prefix()
and return that value as-is. A subclass may override by assigningtemplate_prefix
.
- classmethod get_url_prefix()[source]¶
Returns the “URL prefix” for the master view. This prefix is used for all URLs defined by the view class.
Using the same example as in
get_route_prefix()
, the URL prefix would be'/widgets'
and the view would have defined routes for these URLs:/widgets/
/widgets/new
/widgets/XXX/edit
/widgets/XXX/delete
The default logic will call
get_route_prefix()
and simply add a'/'
to the beginning. A subclass may override by assigningurl_prefix
.
- grid_render_bool(record, key, value)[source]¶
Custom grid value renderer for “boolean” fields.
This converts a bool value to “Yes” or “No” - unless the value is
None
in which case this renders empty string. To use this feature for your grid:grid.set_renderer('my_bool_field', self.grid_render_bool)
- grid_render_currency(record, key, value, scale=2)[source]¶
Custom grid value renderer for “currency” fields.
This expects float or decimal values, and will round the decimal as appropriate, and add the currency symbol.
- Parameters:
scale – Number of decimal digits to be displayed; default is 2 places.
To use this feature for your grid:
grid.set_renderer('my_currency_field', self.grid_render_currency) # you can also override scale grid.set_renderer('my_currency_field', self.grid_render_currency, scale=4)
- grid_render_datetime(record, key, value, fmt=None)[source]¶
Custom grid value renderer for
datetime
fields.- Parameters:
fmt – Optional format string to use instead of the default:
'%Y-%m-%d %I:%M:%S %p'
To use this feature for your grid:
grid.set_renderer('my_datetime_field', self.grid_render_datetime) # you can also override format grid.set_renderer('my_datetime_field', self.grid_render_datetime, fmt='%Y-%m-%d %H:%M:%S')
- grid_render_enum(record, key, value, enum=None)[source]¶
Custom grid value renderer for “enum” fields.
- Parameters:
enum – Enum class for the field. This should be an instance of
Enum
.
To use this feature for your grid:
from enum import Enum class MyEnum(Enum): ONE = 1 TWO = 2 THREE = 3 grid.set_renderer('my_enum_field', self.grid_render_enum, enum=MyEnum)
- grid_render_notes(record, key, value, maxlen=100)[source]¶
Custom grid value renderer for “notes” fields.
If the given text
value
is shorter thanmaxlen
characters, it is returned as-is.But if it is longer, then it is truncated and an ellispsis is added. The resulting
<span>
tag is also given atitle
attribute with the original (full) text, so that appears on mouse hover.To use this feature for your grid:
grid.set_renderer('my_notes_field', self.grid_render_notes) # you can also override maxlen grid.set_renderer('my_notes_field', self.grid_render_notes, maxlen=50)
- has_any_perm(*names)[source]¶
Shortcut to check if current user has any of the given permissions.
This calls
has_perm()
until one returnsTrue
. If none do, returnsFalse
.
- has_perm(name)[source]¶
Shortcut to check if current user has the given permission.
This will automatically add the
permission_prefix
toname
before passing it on tohas_perm()
.For instance within the
UserView
these give the same result:self.request.has_perm('users.edit') self.has_perm('edit')
So this shortcut only applies to permissions defined for the current master view. The first example above must still be used to check for “foreign” permissions (i.e. any needing a different prefix).
- index()[source]¶
View to “list” (filter/browse) the model data.
This is the “default” view for the model and is what user sees when visiting the “root” path under the
url_prefix
, e.g./widgets/
.By default, this view is included only if
listable
is true.The default view logic will show a “grid” (table) with the model data (unless
has_grid
is false).See also related methods, which are called by this one:
- is_deletable(obj)[source]¶
Returns a boolean indicating whether “delete” should be allowed for the given model instance (and for current user).
By default this always return
True
; subclass can override if needed.Note that the use of this method implies
deletable
is true, so the method does not need to check that flag.
- is_editable(obj)[source]¶
Returns a boolean indicating whether “edit” should be allowed for the given model instance (and for current user).
By default this always return
True
; subclass can override if needed.Note that the use of this method implies
editable
is true, so the method does not need to check that flag.
- make_button(label, variant=None, primary=False, **kwargs)[source]¶
Make and return a HTML
<b-button>
literal.- Parameters:
label – Text label for the button.
variant – This is the “Buefy type” (or “Oruga variant”) for the button. Buefy and Oruga represent this differently but this logic expects the Buefy format (e.g.
is-danger
) and not the Oruga format (e.g.danger
), despite the param name matching Oruga’s terminology.type – This param is not advertised in the method signature, but if caller specifies
type
instead ofvariant
it should work the same.primary –
If neither
variant
nortype
are specified, this flag may be used to automatically set the Buefy type tois-primary
.This is the preferred method where applicable, since it avoids the Buefy vs. Oruga confusion, and the implementation can change in the future.
**kwargs – All remaining kwargs are passed to the underlying
HTML.tag()
call, so will be rendered as attributes on the button tag.
- Returns:
HTML literal for the button element. Will be something along the lines of:
<b-button type="is-primary" icon-pack="fas" icon-left="hand-pointer"> Click Me </b-button>
- make_model_form(model_instance=None, **kwargs)[source]¶
Create and return a
Form
for the view model.Note that this method is called for multiple “CRUD” views, e.g.:
See also related methods, which are called by this one:
- make_model_grid(session=None, **kwargs)[source]¶
Create and return a
Grid
instance for use with theindex()
view.See also related methods, which are called by this one:
- make_progress(key, **kwargs)[source]¶
Create and return a
SessionProgress
instance, with the given key.This is normally done just before calling
render_progress()
.
- objectify(form)[source]¶
Must return a “model instance” object which reflects the validated form data.
In simple cases this may just return the
validated
data dict.When dealing with SQLAlchemy models it would return a proper mapped instance, creating it if necessary.
- Parameters:
form – Reference to the already validated
Form
object. See the form’svalidated
attribute for the data.
See also
edit_save_form()
which calls this method.
- persist(obj, session=None)[source]¶
If applicable, this method should persist (“save”) the given object’s data (e.g. to DB), creating or updating it as needed.
This is part of the “submit form” workflow;
obj
should be a model instance which already reflects the validated form data.Note that there is no default logic here, subclass must override if needed.
- Parameters:
obj – Model instance object as produced by
objectify()
.
See also
edit_save_form()
which calls this method.
- render_progress(progress, context=None, template=None)[source]¶
Render the progress page, with given template/context.
When a view method needs to start a long-running operation, it first starts a thread to do the work, and then it renders the “progress” page. As the operation continues the progress page is updated. When the operation completes (or fails) the user is redirected to the final destination.
TODO: should document more about how to do this..
- Parameters:
progress – Progress indicator instance as returned by
make_progress()
.- Returns:
A response with rendered progress page.
- render_to_response(template, context)[source]¶
Locate and render an appropriate template, with the given context, and return a response.
The specified
template
should be only the “base name” for the template - e.g.'index'
or'edit'
. This method will then try to locate a suitable template file, based on values fromget_template_prefix()
andget_fallback_templates()
.In practice this usually means two different template paths will be attempted, e.g. if
template
is'edit'
andtemplate_prefix
is'/widgets'
:/widgets/edit.mako
/master/edit.mako
The first template found to exist will be used for rendering. It then calls
pyramid.renderers.render_to_response()
and returns the result.- Parameters:
template – Base name for the template.
context – Data dict to be used as template context.
- Returns:
Response object containing the rendered template.
- set_labels(obj)[source]¶
Set label overrides on a form or grid, based on what is defined by the view class and its parent class(es).
This is called automatically from
configure_grid()
andconfigure_form()
.This calls
collect_labels()
to find everything, then it assigns the labels using one of (based onobj
type):
- view()[source]¶
View to “view” details of an existing model record.
This usually corresponds to a URL like
/widgets/XXX
whereXXX
represents the key/ID for the record.By default, this view is included only if
viewable
is true.The default view logic will show a read-only form with field values displayed.
Subclass normally should not override this method, but rather one of the related methods which are called (in)directly by this one: