Add basic "DB picker" support, for views which allow multiple engines
i.e. whichever engine is "current" will determine where data comes from
This commit is contained in:
parent
0d7492f6be
commit
839f6affe2
|
@ -132,6 +132,21 @@
|
||||||
% endif
|
% endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
% if expose_db_picker is not Undefined and expose_db_picker:
|
||||||
|
<div class="level-item">
|
||||||
|
<p>DB:</p>
|
||||||
|
</div>
|
||||||
|
<div class="level-item">
|
||||||
|
${h.form(url('change_db_engine'))}
|
||||||
|
${h.csrf_token(request)}
|
||||||
|
${h.hidden('engine_type', value=master.engine_type_key)}
|
||||||
|
<div class="select">
|
||||||
|
${h.select('dbkey', db_picker_selected, db_picker_options, id='db-picker')}
|
||||||
|
</div>
|
||||||
|
${h.end_form()}
|
||||||
|
</div>
|
||||||
|
% endif
|
||||||
|
|
||||||
</div><!-- level-left -->
|
</div><!-- level-left -->
|
||||||
<div class="level-right">
|
<div class="level-right">
|
||||||
|
|
||||||
|
@ -303,6 +318,13 @@
|
||||||
var session_timeout = ${request.get_session_timeout() or 'null'};
|
var session_timeout = ${request.get_session_timeout() or 'null'};
|
||||||
var logout_url = '${request.route_url('logout')}';
|
var logout_url = '${request.route_url('logout')}';
|
||||||
var noop_url = '${request.route_url('noop')}';
|
var noop_url = '${request.route_url('noop')}';
|
||||||
|
% if expose_db_picker is not Undefined and expose_db_picker:
|
||||||
|
$(function() {
|
||||||
|
$('#db-picker').change(function() {
|
||||||
|
$(this).parents('form:first').submit();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
% endif
|
||||||
% if expose_theme_picker and request.has_perm('common.change_app_theme'):
|
% if expose_theme_picker and request.has_perm('common.change_app_theme'):
|
||||||
$(function() {
|
$(function() {
|
||||||
$('#theme-picker').change(function() {
|
$('#theme-picker').change(function() {
|
||||||
|
|
|
@ -143,6 +143,20 @@ class CommonView(View):
|
||||||
self.request.session.flash("App theme has been changed to: {}".format(theme))
|
self.request.session.flash("App theme has been changed to: {}".format(theme))
|
||||||
return self.redirect(self.request.get_referrer())
|
return self.redirect(self.request.get_referrer())
|
||||||
|
|
||||||
|
def change_db_engine(self):
|
||||||
|
"""
|
||||||
|
Simple view which can change user's "current" database engine, of a
|
||||||
|
given type, then redirect back to referring page.
|
||||||
|
"""
|
||||||
|
engine_type = self.request.POST.get('engine_type')
|
||||||
|
if engine_type:
|
||||||
|
dbkey = self.request.POST.get('dbkey')
|
||||||
|
if dbkey:
|
||||||
|
self.request.session['tailbone.engines.{}.current'.format(engine_type)] = dbkey
|
||||||
|
if self.rattail_config.getbool('tailbone', 'engines.flash_after_change', default=True):
|
||||||
|
self.request.session.flash("Switched '{}' database to: {}".format(engine_type, dbkey))
|
||||||
|
return self.redirect(self.request.get_referrer())
|
||||||
|
|
||||||
def feedback(self):
|
def feedback(self):
|
||||||
"""
|
"""
|
||||||
Generic view to handle the user feedback form.
|
Generic view to handle the user feedback form.
|
||||||
|
@ -212,6 +226,12 @@ class CommonView(View):
|
||||||
config.add_route('mobile.about', '/mobile/about')
|
config.add_route('mobile.about', '/mobile/about')
|
||||||
config.add_view(cls, attr='about', route_name='mobile.about', renderer='/mobile/about.mako')
|
config.add_view(cls, attr='about', route_name='mobile.about', renderer='/mobile/about.mako')
|
||||||
|
|
||||||
|
# change db engine
|
||||||
|
config.add_tailbone_permission('common', 'common.change_db_engine',
|
||||||
|
"Change which Database Engine is active (for user)")
|
||||||
|
config.add_route('change_db_engine', '/change-db-engine', request_method='POST')
|
||||||
|
config.add_view(cls, attr='change_db_engine', route_name='change_db_engine')
|
||||||
|
|
||||||
# change theme
|
# change theme
|
||||||
config.add_tailbone_permission('common', 'common.change_app_theme',
|
config.add_tailbone_permission('common', 'common.change_app_theme',
|
||||||
"Change global App Template Theme")
|
"Change global App Template Theme")
|
||||||
|
|
|
@ -36,6 +36,7 @@ import sqlalchemy as sa
|
||||||
from sqlalchemy import orm
|
from sqlalchemy import orm
|
||||||
|
|
||||||
import sqlalchemy_continuum as continuum
|
import sqlalchemy_continuum as continuum
|
||||||
|
from sqlalchemy_utils.functions import get_primary_keys
|
||||||
|
|
||||||
from rattail.db import model, Session as RattailSession
|
from rattail.db import model, Session as RattailSession
|
||||||
from rattail.db.continuum import model_transaction_query
|
from rattail.db.continuum import model_transaction_query
|
||||||
|
@ -47,6 +48,7 @@ from rattail.csvutil import UnicodeDictWriter
|
||||||
from rattail.files import temp_path
|
from rattail.files import temp_path
|
||||||
from rattail.excel import ExcelWriter
|
from rattail.excel import ExcelWriter
|
||||||
from rattail.gpc import GPC
|
from rattail.gpc import GPC
|
||||||
|
from rattail.util import OrderedDict
|
||||||
|
|
||||||
import colander
|
import colander
|
||||||
import deform
|
import deform
|
||||||
|
@ -124,6 +126,11 @@ class MasterView(View):
|
||||||
has_image = False
|
has_image = False
|
||||||
has_thumbnail = False
|
has_thumbnail = False
|
||||||
|
|
||||||
|
# can set this to true, and set type key as needed, and implement some
|
||||||
|
# other things also, to get a DB picker in the header for all views
|
||||||
|
supports_multiple_engines = False
|
||||||
|
engine_type_key = 'rattail'
|
||||||
|
|
||||||
row_attrs = {}
|
row_attrs = {}
|
||||||
cell_attrs = {}
|
cell_attrs = {}
|
||||||
|
|
||||||
|
@ -2096,8 +2103,9 @@ class MasterView(View):
|
||||||
"""
|
"""
|
||||||
if hasattr(cls, 'model_key'):
|
if hasattr(cls, 'model_key'):
|
||||||
return cls.model_key
|
return cls.model_key
|
||||||
mapper = orm.class_mapper(cls.get_model_class())
|
|
||||||
return ','.join([k.key for k in mapper.primary_key])
|
pkeys = get_primary_keys(cls.get_model_class())
|
||||||
|
return ','.join(pkeys)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_model_title(cls):
|
def get_model_title(cls):
|
||||||
|
@ -2323,12 +2331,50 @@ class MasterView(View):
|
||||||
return ['/mobile/master/{}.mako'.format(template)]
|
return ['/mobile/master/{}.mako'.format(template)]
|
||||||
return ['/master/{}.mako'.format(template)]
|
return ['/master/{}.mako'.format(template)]
|
||||||
|
|
||||||
|
def get_current_engine_dbkey(self):
|
||||||
|
"""
|
||||||
|
Returns the "current" engine's dbkey, for the current user.
|
||||||
|
"""
|
||||||
|
return self.request.session.get('tailbone.engines.{}.current'.format(self.engine_type_key),
|
||||||
|
'default')
|
||||||
|
|
||||||
def template_kwargs(self, **kwargs):
|
def template_kwargs(self, **kwargs):
|
||||||
"""
|
"""
|
||||||
Supplement the template context, for all views.
|
Supplement the template context, for all views.
|
||||||
"""
|
"""
|
||||||
|
# whether or not to show the DB picker?
|
||||||
|
kwargs['expose_db_picker'] = False
|
||||||
|
if self.supports_multiple_engines:
|
||||||
|
|
||||||
|
# view declares support for multiple engines, but we only want to
|
||||||
|
# show the picker if we have more than one engine configured
|
||||||
|
engines = self.get_db_engines()
|
||||||
|
if len(engines) > 1:
|
||||||
|
|
||||||
|
# user session determines "current" db engine *of this type*
|
||||||
|
# (note that many master views may declare the same type, and
|
||||||
|
# would therefore share the "current" engine)
|
||||||
|
selected = self.get_current_engine_dbkey()
|
||||||
|
kwargs['expose_db_picker'] = True
|
||||||
|
kwargs['db_picker_options'] = [tags.Option(k) for k in engines]
|
||||||
|
kwargs['db_picker_selected'] = selected
|
||||||
|
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
|
def get_db_engines(self):
|
||||||
|
"""
|
||||||
|
Must return a dict (or even better, OrderedDict) which contains all
|
||||||
|
supported database engines for the master view. Used with the DB
|
||||||
|
picker feature.
|
||||||
|
"""
|
||||||
|
engines = OrderedDict()
|
||||||
|
if self.rattail_config.rattail_engine:
|
||||||
|
engines['default'] = self.rattail_config.rattail_engine
|
||||||
|
for dbkey in sorted(self.rattail_config.rattail_engines):
|
||||||
|
if dbkey != 'default':
|
||||||
|
engines[dbkey] = self.rattail_config.rattail_engines[dbkey]
|
||||||
|
return engines
|
||||||
|
|
||||||
##############################
|
##############################
|
||||||
# Grid Stuff
|
# Grid Stuff
|
||||||
##############################
|
##############################
|
||||||
|
@ -2446,7 +2492,8 @@ class MasterView(View):
|
||||||
except orm.exc.UnmappedInstanceError:
|
except orm.exc.UnmappedInstanceError:
|
||||||
return {self.model_key: row[self.model_key]}
|
return {self.model_key: row[self.model_key]}
|
||||||
else:
|
else:
|
||||||
keys = [k.key for k in mapper.primary_key]
|
pkeys = get_primary_keys(row)
|
||||||
|
keys = list(pkeys)
|
||||||
values = [getattr(row, k) for k in keys]
|
values = [getattr(row, k) for k in keys]
|
||||||
return dict(zip(keys, values))
|
return dict(zip(keys, values))
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue