Add support for "delete set" feature for main object index view

aka. "delete selected objects"
This commit is contained in:
Lance Edgar 2019-02-02 19:34:36 -06:00
parent 5ec11cf5b8
commit 84fc3e7d50

View file

@ -82,6 +82,7 @@ class MasterView(View):
editable = True editable = True
deletable = True deletable = True
bulk_deletable = False bulk_deletable = False
set_deletable = False
populatable = False populatable = False
mergeable = False mergeable = False
downloadable = False downloadable = False
@ -326,6 +327,14 @@ class MasterView(View):
Return a dictionary of kwargs to be passed to the factory when creating Return a dictionary of kwargs to be passed to the factory when creating
new grid instances. new grid instances.
""" """
permission_prefix = self.get_permission_prefix()
checkboxes = self.checkboxes
if not checkboxes and self.mergeable and self.request.has_perm('{}.merge'.format(permission_prefix)):
checkboxes = True
if not checkboxes and self.set_deletable and self.request.has_perm('{}.delete_set'.format(permission_prefix)):
checkboxes = True
defaults = { defaults = {
'model_class': getattr(self, 'model_class', None), 'model_class': getattr(self, 'model_class', None),
'width': 'full', 'width': 'full',
@ -335,8 +344,7 @@ class MasterView(View):
'pageable': self.pageable, 'pageable': self.pageable,
'extra_row_class': self.grid_extra_class, 'extra_row_class': self.grid_extra_class,
'url': lambda obj: self.get_action_url('view', obj), 'url': lambda obj: self.get_action_url('view', obj),
'checkboxes': self.checkboxes or ( 'checkboxes': checkboxes,
self.mergeable and self.request.has_perm('{}.merge'.format(self.get_permission_prefix()))),
'checked': self.checked, 'checked': self.checked,
} }
if 'main_actions' not in kwargs and 'more_actions' not in kwargs: if 'main_actions' not in kwargs and 'more_actions' not in kwargs:
@ -1569,19 +1577,15 @@ class MasterView(View):
""" """
Delete all records matching the current grid query Delete all records matching the current grid query
""" """
if self.request.method == 'POST': objects = self.get_effective_data()
objects = self.get_effective_data() key = '{}.bulk_delete'.format(self.model_class.__tablename__)
key = '{}.bulk_delete'.format(self.model_class.__tablename__) progress = SessionProgress(self.request, key)
progress = SessionProgress(self.request, key) thread = Thread(target=self.bulk_delete_thread, args=(objects, progress))
thread = Thread(target=self.bulk_delete_thread, args=(objects, progress)) thread.start()
thread.start() return self.render_progress(progress, {
return self.render_progress(progress, { 'cancel_url': self.get_index_url(),
'cancel_url': self.get_index_url(), 'cancel_msg': "Bulk deletion was canceled",
'cancel_msg': "Bulk deletion was canceled", })
})
else:
self.request.session.flash("Sorry, you must POST to do a bulk delete operation")
return self.redirect(self.get_index_url())
def bulk_delete_objects(self, session, objects, progress=None): def bulk_delete_objects(self, session, objects, progress=None):
@ -1626,6 +1630,26 @@ class MasterView(View):
progress.session['success_url'] = self.get_index_url() progress.session['success_url'] = self.get_index_url()
progress.session.save() progress.session.save()
def delete_set(self):
"""
View which can delete a specific set of records.
"""
# TODO: should have a cleaner way to parse object uuids?
uuids = self.request.POST.get('uuids')
if uuids:
uuids = uuids.split(',')
# TODO: probably need to allow override of fetcher callable
fetcher = lambda uuid: self.Session.query(self.model_class).get(uuid)
deleted = 0
for uuid in uuids:
obj = fetcher(uuid)
if obj:
self.delete_instance(obj)
deleted += 1
model_title_plural = self.get_model_title_plural()
self.request.session.flash("Deleted {} {}".format(deleted, model_title_plural))
return self.redirect(self.get_index_url())
def oneoff_import(self, importer, host_object=None): def oneoff_import(self, importer, host_object=None):
""" """
Basic helper method, to do a one-off import (or export, depending on Basic helper method, to do a one-off import (or export, depending on
@ -3057,12 +3081,22 @@ class MasterView(View):
# bulk delete # bulk delete
if cls.bulk_deletable: if cls.bulk_deletable:
config.add_route('{}.bulk_delete'.format(route_prefix), '{}/bulk-delete'.format(url_prefix)) config.add_route('{}.bulk_delete'.format(route_prefix), '{}/bulk-delete'.format(url_prefix),
request_method='POST')
config.add_view(cls, attr='bulk_delete', route_name='{}.bulk_delete'.format(route_prefix), config.add_view(cls, attr='bulk_delete', route_name='{}.bulk_delete'.format(route_prefix),
permission='{}.bulk_delete'.format(permission_prefix)) permission='{}.bulk_delete'.format(permission_prefix))
config.add_tailbone_permission(permission_prefix, '{}.bulk_delete'.format(permission_prefix), config.add_tailbone_permission(permission_prefix, '{}.bulk_delete'.format(permission_prefix),
"Bulk delete {}".format(model_title_plural)) "Bulk delete {}".format(model_title_plural))
# delete set
if cls.set_deletable:
config.add_tailbone_permission(permission_prefix, '{}.delete_set'.format(permission_prefix),
"Delete set (selection) of {}".format(model_title_plural))
config.add_route('{}.delete_set'.format(route_prefix), '{}/delete-set'.format(url_prefix),
request_method='POST')
config.add_view(cls, attr='delete_set', route_name='{}.delete_set'.format(route_prefix),
permission='{}.delete_set'.format(permission_prefix))
# merge # merge
if cls.mergeable: if cls.mergeable:
config.add_route('{}.merge'.format(route_prefix), '{}/merge'.format(url_prefix)) config.add_route('{}.merge'.format(route_prefix), '{}/merge'.format(url_prefix))