tailbone/tailbone/grids/util.py
2013-09-01 08:18:37 -07:00

139 lines
4.1 KiB
Python

#!/usr/bin/env python
# -*- coding: utf-8 -*-
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2012 Lance Edgar
#
# This file is part of Rattail.
#
# Rattail is free software: you can redistribute it and/or modify it under the
# terms of the GNU Affero General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option)
# any later version.
#
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
# more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with Rattail. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Grid Utilities
"""
from sqlalchemy.orm.attributes import InstrumentedAttribute
from webhelpers.html import literal
from pyramid.response import Response
from .search import SearchFormRenderer
def get_sort_config(name, request, **kwargs):
"""
Returns a configuration dictionary for grid sorting.
"""
# Initial config uses some default values.
config = {
'dir': 'asc',
'per_page': 20,
'page': 1,
}
# Override with defaults provided by caller.
config.update(kwargs)
# Override with values from GET/POST request and/or session.
for key in config:
full_key = name+'_'+key
if request.params.get(key):
value = request.params[key]
config[key] = value
request.session[full_key] = value
elif request.session.get(full_key):
value = request.session[full_key]
config[key] = value
return config
def get_sort_map(cls, names=None, **kwargs):
"""
Convenience function which returns a sort map for ``cls``.
If ``names`` is not specified, the map will include all "standard" fields
present on the mapped class. Otherwise, the map will be limited to only
the fields which are named.
All remaining ``kwargs`` are assumed to be sort map entries, and will be
added to the map directly.
"""
smap = {}
if names is None:
names = []
for attr in cls.__dict__:
obj = getattr(cls, attr)
if isinstance(obj, InstrumentedAttribute):
if obj.key != 'uuid':
names.append(obj.key)
for name in names:
smap[name] = sorter(getattr(cls, name))
smap.update(kwargs)
return smap
def render_grid(grid, search_form=None, **kwargs):
"""
Convenience function to render ``grid`` (which should be a
:class:`tailbone.grids.Grid` instance).
This "usually" will return a dictionary to be used as context for rendering
the final view template.
However, if a partial grid is requested (or mandated), then the grid body
will be rendered and a :class:`pyramid.response.Response` object will be
returned instead.
"""
if grid.partial_only or grid.request.params.get('partial'):
return Response(body=grid.render(), content_type='text/html')
kwargs['grid'] = literal(grid.render())
if search_form:
kwargs['search'] = SearchFormRenderer(search_form)
return kwargs
def sort_query(query, config, sort_map, join_map={}):
"""
Sorts ``query`` according to ``config`` and ``sort_map``. ``join_map`` is
used, if necessary, to join additional tables to the base query. The
sorted query is returned.
"""
field = config.get('sort')
if not field:
return query
joins = config.setdefault('joins', [])
if field in join_map and field not in joins:
query = join_map[field](query)
joins.append(field)
sort = sort_map[field]
return sort(query, config['dir'])
def sorter(field):
"""
Returns a function suitable for a sort map callable, with typical logic
built in for sorting applied to ``field``.
"""
return lambda q, d: q.order_by(getattr(field, d)())