Refacto ActionView into MultipleObjectFormActionView and MultipleObjectConfirmActionView.

Split ActionView into smaller mixins.
This commit is contained in:
Roberto Rosario
2016-12-21 03:27:27 -04:00
parent c262ccabbd
commit c21eb6d4cf
2 changed files with 138 additions and 108 deletions

View File

@@ -3,9 +3,8 @@ from __future__ import absolute_import, unicode_literals
from django.conf import settings
from django.contrib import messages
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import PermissionDenied
from django.http import HttpResponseRedirect
from django.utils.translation import ungettext, ugettext_lazy as _
from django.utils.translation import ugettext_lazy as _
from django.views.generic import (
FormView as DjangoFormView, DetailView, TemplateView
)
@@ -18,121 +17,38 @@ from django.views.generic.list import ListView
from django_downloadview import VirtualDownloadView, VirtualFile
from pure_pagination.mixins import PaginationMixin
from acls.models import AccessControlList
from .forms import ChoiceForm
from .mixins import * # NOQA
from .settings import setting_paginate_by
__all__ = (
'ActionView', 'AssignRemoveView', 'ConfirmView', 'FormView',
'MultiFormView', 'SingleObjectCreateView', 'SingleObjectDeleteView',
'AssignRemoveView', 'ConfirmView', 'FormView', 'MultiFormView',
'MultipleObjectConfirmActionView', 'MultipleObjectFormActionView',
'SingleObjectCreateView', 'SingleObjectDeleteView',
'SingleObjectDetailView', 'SingleObjectEditView', 'SingleObjectListView',
'SimpleView',
'SimpleView'
)
class ActionView(ViewPermissionCheckMixin, ExtraContextMixin, RedirectionMixin, DjangoFormView):
class MultipleObjectFormActionView(ObjectActionMixin, MultipleObjectMixin, FormExtraKwargsMixin, ViewPermissionCheckMixin, ExtraContextMixin, RedirectionMixin, DjangoFormView):
"""
This view will present a form and upon receiving a POST request will
perform an action on an object or queryset
"""
queryset = None
model = None
pk_url_kwarg = 'pk'
object_permission = None
slug_url_kwarg = 'slug'
success_message = 'Operation performed on %(count)d object'
success_message_plural = 'Operation performed on %(count)d objects'
template_name = 'appearance/generic_form.html'
def form_valid(self, form):
self.view_action(form=form)
return super(ActionView, self).form_valid(form=form)
return super(MultipleObjectFormActionView, self).form_valid(form=form)
def get_form_extra_kwargs(self):
return {}
def get_form_kwargs(self):
result = super(ActionView, self).get_form_kwargs()
result.update(self.get_form_extra_kwargs())
return result
class MultipleObjectConfirmActionView(ObjectActionMixin, MultipleObjectMixin, ViewPermissionCheckMixin, ExtraContextMixin, RedirectionMixin, TemplateView):
template_name = 'appearance/generic_confirm.html'
def get_pk_list(self):
result = self.request.GET.get(
'id_list', self.request.POST.get('id_list')
)
if result:
return result.split(',')
else:
return None
def get_queryset(self):
if self.queryset is not None:
queryset = self.queryset
if isinstance(queryset, QuerySet):
queryset = queryset.all()
elif self.model is not None:
queryset = self.model._default_manager.all()
pk = self.kwargs.get(self.pk_url_kwarg)
slug = self.kwargs.get(self.slug_url_kwarg)
pk_list = self.get_pk_list()
if pk is not None:
queryset = queryset.filter(pk=pk)
# Next, try looking up by slug.
if slug is not None and (pk is None or self.query_pk_and_slug):
slug_field = self.get_slug_field()
queryset = queryset.filter(**{slug_field: slug})
if pk_list is not None:
queryset = queryset.filter(pk__in=self.get_pk_list())
if pk is None and slug is None and pk_list is None:
raise AttributeError(
'Generic detail view %s must be called with '
'either an object pk, a slug or an id list.'
% self.__class__.__name__
)
if self.object_permission:
return AccessControlList.objects.filter_by_access(
self.object_permission, self.request.user, queryset=queryset
)
else:
return queryset
def get_success_message(self, count):
return ungettext(
self.success_message,
self.success_message_plural,
count
) % {
'count': count,
}
def object_action(self, form, instance):
pass
def view_action(self, form):
count = 0
for instance in self.get_queryset():
try:
self.object_action(form=form, instance=instance)
except PermissionDenied:
pass
else:
count += 1
messages.success(
self.request,
self.get_success_message(count=count)
)
def post(self, request, *args, **kwargs):
self.view_action()
return HttpResponseRedirect(self.get_success_url())
class AssignRemoveView(ExtraContextMixin, ViewPermissionCheckMixin, ObjectPermissionCheckMixin, TemplateView):

View File

@@ -1,17 +1,21 @@
from __future__ import unicode_literals
from django.apps import apps
from django.conf import settings
from django.contrib import messages
from django.core.exceptions import PermissionDenied
from django.core.urlresolvers import reverse
from django.db.models.query import QuerySet
from django.http import HttpResponseRedirect
from django.utils.translation import ungettext, ugettext_lazy as _
from permissions import Permission
from acls.models import AccessControlList
__all__ = (
'DeleteExtraDataMixin', 'ExtraContextMixin',
'DeleteExtraDataMixin', 'ExtraContextMixin', 'FormExtraKwargsMixin',
'MultipleObjectMixin', 'ObjectActionMixin',
'ObjectListPermissionFilterMixin', 'ObjectNameMixin',
'ObjectPermissionCheckMixin', 'RedirectionMixin',
'ViewPermissionCheckMixin'
@@ -30,7 +34,27 @@ class DeleteExtraDataMixin(object):
return HttpResponseRedirect(success_url)
class FormExtraKwargsMixin(object):
"""
Mixin that allows a view to pass extra keyword arguments to forms
"""
form_extra_kwargs = {}
def get_form_extra_kwargs(self):
return self.form_extra_kwargs
def get_form_kwargs(self):
result = super(FormExtraKwargsMixin, self).get_form_kwargs()
result.update(self.get_form_extra_kwargs())
return result
class ExtraContextMixin(object):
"""
Mixin that allows views to pass extra context to the template
"""
extra_context = {}
def get_extra_context(self):
@@ -44,8 +68,8 @@ class ExtraContextMixin(object):
class MultipleInstanceActionMixin(object):
model = None
success_message = 'Operation performed on %(count)d object'
success_message_plural = 'Operation performed on %(count)d objects'
success_message = _('Operation performed on %(count)d object')
success_message_plural = _('Operation performed on %(count)d objects')
def get_pk_list(self):
return self.request.GET.get(
@@ -82,14 +106,108 @@ class MultipleInstanceActionMixin(object):
return HttpResponseRedirect(self.get_success_url())
class MultipleObjectMixin(object):
"""
Mixin that allows a view to work on a single or multiple objects
"""
model = None
object_permission = None
pk_list_key = 'id_list'
pk_list_separator = ','
pk_url_kwarg = 'pk'
queryset = None
slug_url_kwarg = 'slug'
def get_pk_list(self):
result = self.request.GET.get(
self.pk_list_key, self.request.POST.get(self.pk_list_key)
)
if result:
return result.split(self.pk_list_separator)
else:
return None
def get_queryset(self):
if self.queryset is not None:
queryset = self.queryset
if isinstance(queryset, QuerySet):
queryset = queryset.all()
elif self.model is not None:
queryset = self.model._default_manager.all()
pk = self.kwargs.get(self.pk_url_kwarg)
slug = self.kwargs.get(self.slug_url_kwarg)
pk_list = self.get_pk_list()
if pk is not None:
queryset = queryset.filter(pk=pk)
# Next, try looking up by slug.
if slug is not None and (pk is None or self.query_pk_and_slug):
slug_field = self.get_slug_field()
queryset = queryset.filter(**{slug_field: slug})
if pk_list is not None:
queryset = queryset.filter(pk__in=self.get_pk_list())
if pk is None and slug is None and pk_list is None:
raise AttributeError(
'Generic detail view %s must be called with '
'either an object pk, a slug or an id list.'
% self.__class__.__name__
)
if self.object_permission:
return AccessControlList.objects.filter_by_access(
self.object_permission, self.request.user, queryset=queryset
)
else:
return queryset
class ObjectActionMixin(object):
"""
Mixin that performs an user action to a queryset
"""
success_message = 'Operation performed on %(count)d object'
success_message_plural = 'Operation performed on %(count)d objects'
def get_success_message(self, count):
return ungettext(
self.success_message,
self.success_message_plural,
count
) % {
'count': count,
}
def object_action(self, instance, form=None):
pass
def view_action(self, form=None):
count = 0
for instance in self.get_queryset():
try:
self.object_action(form=form, instance=instance)
except PermissionDenied:
pass
else:
count += 1
messages.success(
self.request,
self.get_success_message(count=count)
)
class ObjectListPermissionFilterMixin(object):
object_permission = None
def get_queryset(self):
AccessControlList = apps.get_model(
app_label='acls', model_name='AccessControlList'
)
queryset = super(ObjectListPermissionFilterMixin, self).get_queryset()
if self.object_permission:
@@ -123,10 +241,6 @@ class ObjectPermissionCheckMixin(object):
return self.get_object()
def dispatch(self, request, *args, **kwargs):
AccessControlList = apps.get_model(
app_label='acls', model_name='AccessControlList'
)
if self.object_permission:
AccessControlList.objects.check_access(
permissions=self.object_permission, user=request.user,