Add new BatchMasterView
for new-style batches.
This commit is contained in:
parent
7338560fc3
commit
62221a1a25
14 changed files with 1112 additions and 93 deletions
File diff suppressed because it is too large
Load diff
|
@ -2,7 +2,7 @@
|
|||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2015 Lance Edgar
|
||||
# Copyright © 2010-2016 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
|
@ -24,7 +24,9 @@
|
|||
Model Master View
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
import re
|
||||
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import orm
|
||||
|
@ -100,18 +102,24 @@ class MasterView(View):
|
|||
View for creating a new model record.
|
||||
"""
|
||||
self.creating = True
|
||||
form = self.make_form(self.model_class)
|
||||
form = self.make_form(self.get_model_class())
|
||||
if self.request.method == 'POST':
|
||||
if form.validate():
|
||||
self.before_create(form)
|
||||
form.save()
|
||||
self.save_create_form(form)
|
||||
instance = form.fieldset.model
|
||||
self.after_create(instance)
|
||||
self.request.session.flash("{} {} has been created.".format(
|
||||
self.get_model_title(), instance))
|
||||
return self.redirect(self.get_action_url('view', instance))
|
||||
return self.redirect_after_create(instance)
|
||||
return self.render_to_response('create', {'form': form})
|
||||
|
||||
def save_create_form(self, form):
|
||||
self.before_create(form)
|
||||
form.save()
|
||||
|
||||
def redirect_after_create(self, instance):
|
||||
return self.redirect(self.get_action_url('view', instance))
|
||||
|
||||
def view(self):
|
||||
"""
|
||||
View for viewing details of an existing model record.
|
||||
|
@ -119,9 +127,12 @@ class MasterView(View):
|
|||
self.viewing = True
|
||||
instance = self.get_instance()
|
||||
form = self.make_form(instance)
|
||||
return self.render_to_response('view', {'instance': instance,
|
||||
'instance_title': self.get_instance_title(instance),
|
||||
'form': form})
|
||||
return self.render_to_response('view', {
|
||||
'instance': instance,
|
||||
'instance_title': self.get_instance_title(instance),
|
||||
'instance_editable': self.editable_instance(instance),
|
||||
'instance_deletable': self.deletable_instance(instance),
|
||||
'form': form})
|
||||
|
||||
def edit(self):
|
||||
"""
|
||||
|
@ -130,16 +141,26 @@ class MasterView(View):
|
|||
self.editing = True
|
||||
instance = self.get_instance()
|
||||
form = self.make_form(instance)
|
||||
|
||||
if self.request.method == 'POST':
|
||||
if form.validate():
|
||||
self.save_form(form)
|
||||
self.after_edit(instance)
|
||||
self.save_edit_form(form)
|
||||
self.request.session.flash("{0} {1} has been updated.".format(
|
||||
self.get_model_title(), self.get_instance_title(instance)))
|
||||
return self.redirect(self.get_action_url('view', instance))
|
||||
return self.render_to_response('edit', {'instance': instance,
|
||||
'instance_title': self.get_instance_title(instance),
|
||||
'form': form})
|
||||
return self.redirect_after_edit(instance)
|
||||
|
||||
return self.render_to_response('edit', {
|
||||
'instance': instance,
|
||||
'instance_title': self.get_instance_title(instance),
|
||||
'instance_deletable': self.deletable_instance(instance),
|
||||
'form': form})
|
||||
|
||||
def save_edit_form(self, form):
|
||||
self.save_form(form)
|
||||
self.after_edit(form.fieldset.model)
|
||||
|
||||
def redirect_after_edit(self, instance):
|
||||
return self.redirect(self.get_action_url('view', instance))
|
||||
|
||||
def delete(self):
|
||||
"""
|
||||
|
@ -181,7 +202,7 @@ class MasterView(View):
|
|||
Returns the data model class for which the master view exists.
|
||||
"""
|
||||
if not hasattr(cls, 'model_class') and error:
|
||||
raise NotImplementedError("You must define the `model_class` for: {0}".format(cls))
|
||||
raise NotImplementedError("You must define the `model_class` for: {}".format(cls))
|
||||
return getattr(cls, 'model_class', None)
|
||||
|
||||
@classmethod
|
||||
|
@ -213,7 +234,9 @@ class MasterView(View):
|
|||
"""
|
||||
if hasattr(cls, 'model_title'):
|
||||
return cls.model_title
|
||||
return cls.model_class.__name__
|
||||
title = cls.get_model_class().__name__
|
||||
# convert "CamelCase" to "Camel Case"
|
||||
return re.sub(r'([a-z])([A-Z])', r'\g<1> \g<2>', title)
|
||||
|
||||
@classmethod
|
||||
def get_model_title_plural(cls):
|
||||
|
@ -279,7 +302,7 @@ class MasterView(View):
|
|||
If that doesn't work, another attempt will be made using '/master' as
|
||||
the template prefix.
|
||||
"""
|
||||
data.update({
|
||||
context = {
|
||||
'master': self,
|
||||
'model_title': self.get_model_title(),
|
||||
'model_title_plural': self.get_model_title_plural(),
|
||||
|
@ -287,16 +310,33 @@ class MasterView(View):
|
|||
'permission_prefix': self.get_permission_prefix(),
|
||||
'index_url': self.get_index_url(),
|
||||
'action_url': self.get_action_url,
|
||||
})
|
||||
data.update(self.template_kwargs(**data))
|
||||
if hasattr(self, 'template_kwargs_{0}'.format(template)):
|
||||
data.update(getattr(self, 'template_kwargs_{0}'.format(template))(**data))
|
||||
}
|
||||
context.update(data)
|
||||
context.update(self.template_kwargs(**context))
|
||||
if hasattr(self, 'template_kwargs_{}'.format(template)):
|
||||
context.update(getattr(self, 'template_kwargs_{}'.format(template))(**context))
|
||||
|
||||
# First try the template path most specific to the view.
|
||||
try:
|
||||
return render_to_response('{0}/{1}.mako'.format(self.get_template_prefix(), template),
|
||||
data, request=self.request)
|
||||
return render_to_response('{}/{}.mako'.format(self.get_template_prefix(), template),
|
||||
context, request=self.request)
|
||||
|
||||
except IOError:
|
||||
return render_to_response('/master/{0}.mako'.format(template),
|
||||
data, request=self.request)
|
||||
|
||||
# Failing that, try one or more fallback templates.
|
||||
for fallback in self.get_fallback_templates(template):
|
||||
try:
|
||||
return render_to_response(fallback, context, request=self.request)
|
||||
except IOError:
|
||||
pass
|
||||
|
||||
# If we made it all the way here, we found no templates at all, in
|
||||
# which case re-attempt the first and let that error raise on up.
|
||||
return render_to_response('{}/{}.mako'.format(self.get_template_prefix(), template),
|
||||
context, request=self.request)
|
||||
|
||||
def get_fallback_templates(self, template):
|
||||
return ['/master/{}.mako'.format(template)]
|
||||
|
||||
def template_kwargs(self, **kwargs):
|
||||
"""
|
||||
|
@ -439,10 +479,14 @@ class MasterView(View):
|
|||
data = self.get_data(session=kwargs.get('session'))
|
||||
kwargs = self.make_grid_kwargs(**kwargs)
|
||||
grid = factory(key, self.request, data=data, model_class=self.get_model_class(error=False), **kwargs)
|
||||
self._preconfigure_grid(grid)
|
||||
self.configure_grid(grid)
|
||||
grid.load_settings()
|
||||
return grid
|
||||
|
||||
def _preconfigure_grid(self, grid):
|
||||
pass
|
||||
|
||||
def configure_grid(self, grid):
|
||||
"""
|
||||
Configure the grid, customizing as necessary. Subclasses are
|
||||
|
@ -479,7 +523,17 @@ class MasterView(View):
|
|||
users. You would modify the base query to hide what you wanted,
|
||||
regardless of the user's filter selections.
|
||||
"""
|
||||
return session.query(self.model_class)
|
||||
return session.query(self.get_model_class())
|
||||
|
||||
def get_effective_query(self, session):
|
||||
"""
|
||||
Convenience method which returns the "effective" query for the master
|
||||
grid, filtered and sorted to match what would show on the UI, but not
|
||||
paged etc.
|
||||
"""
|
||||
grid = self.make_grid(session=session, pageable=False,
|
||||
main_actions=[], more_actions=[])
|
||||
return grid._fa_grid.rows
|
||||
|
||||
def checkbox(self, instance):
|
||||
"""
|
||||
|
@ -507,7 +561,7 @@ class MasterView(View):
|
|||
doing a database lookup. If the instance cannot be found, raises 404.
|
||||
"""
|
||||
key = self.request.matchdict[self.get_model_key()]
|
||||
instance = self.Session.query(self.model_class).get(key)
|
||||
instance = self.Session.query(self.get_model_class()).get(key)
|
||||
if not instance:
|
||||
raise httpexceptions.HTTPNotFound()
|
||||
return instance
|
||||
|
@ -529,7 +583,9 @@ class MasterView(View):
|
|||
kwargs.setdefault('editing', self.editing)
|
||||
|
||||
fieldset = self.make_fieldset(instance)
|
||||
self._preconfigure_fieldset(fieldset)
|
||||
self.configure_fieldset(fieldset)
|
||||
self._postconfigure_fieldset(fieldset)
|
||||
|
||||
kwargs.setdefault('action_url', self.request.current_route_url(_query=None))
|
||||
if self.creating:
|
||||
|
@ -553,12 +609,18 @@ class MasterView(View):
|
|||
fieldset.prettify = prettify
|
||||
return fieldset
|
||||
|
||||
def _preconfigure_fieldset(self, fieldset):
|
||||
pass
|
||||
|
||||
def configure_fieldset(self, fieldset):
|
||||
"""
|
||||
Configure the given fieldset.
|
||||
"""
|
||||
fieldset.configure()
|
||||
|
||||
def _postconfigure_fieldset(self, fieldset):
|
||||
pass
|
||||
|
||||
def before_create(self, form):
|
||||
"""
|
||||
Event hook, called just after the form to create a new instance has
|
||||
|
@ -570,6 +632,14 @@ class MasterView(View):
|
|||
Event hook, called just after a new instance is saved.
|
||||
"""
|
||||
|
||||
def editable_instance(self, instance):
|
||||
"""
|
||||
Returns boolean indicating whether or not the given instance can be
|
||||
considered "editable". Returns ``True`` by default; override as
|
||||
necessary.
|
||||
"""
|
||||
return True
|
||||
|
||||
def after_edit(self, instance):
|
||||
"""
|
||||
Event hook, called just after an existing instance is saved.
|
||||
|
@ -617,7 +687,7 @@ class MasterView(View):
|
|||
"""
|
||||
Provide default configuration for a master view.
|
||||
"""
|
||||
return cls._defaults(config)
|
||||
cls._defaults(config)
|
||||
|
||||
@classmethod
|
||||
def _defaults(cls, config):
|
||||
|
|
|
@ -339,11 +339,7 @@ class ProductsView(MasterView):
|
|||
Threat target for making a batch from current products query.
|
||||
"""
|
||||
session = RattailSession()
|
||||
|
||||
grid = self.make_grid(session=session, pageable=False,
|
||||
main_actions=[], more_actions=[])
|
||||
products = grid._fa_grid.rows
|
||||
|
||||
products = self.get_effective_query(session)
|
||||
batch = provider.make_batch(session, products, progress)
|
||||
if not batch:
|
||||
session.rollback()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue