Refacto ActionView into MultipleObjectFormActionView and MultipleObjectConfirmActionView.
Split ActionView into smaller mixins.
This commit is contained in:
@@ -3,9 +3,8 @@ from __future__ import absolute_import, unicode_literals
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.core.exceptions import PermissionDenied
|
|
||||||
from django.http import HttpResponseRedirect
|
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 (
|
from django.views.generic import (
|
||||||
FormView as DjangoFormView, DetailView, TemplateView
|
FormView as DjangoFormView, DetailView, TemplateView
|
||||||
)
|
)
|
||||||
@@ -18,121 +17,38 @@ from django.views.generic.list import ListView
|
|||||||
from django_downloadview import VirtualDownloadView, VirtualFile
|
from django_downloadview import VirtualDownloadView, VirtualFile
|
||||||
from pure_pagination.mixins import PaginationMixin
|
from pure_pagination.mixins import PaginationMixin
|
||||||
|
|
||||||
from acls.models import AccessControlList
|
|
||||||
|
|
||||||
from .forms import ChoiceForm
|
from .forms import ChoiceForm
|
||||||
from .mixins import * # NOQA
|
from .mixins import * # NOQA
|
||||||
from .settings import setting_paginate_by
|
from .settings import setting_paginate_by
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'ActionView', 'AssignRemoveView', 'ConfirmView', 'FormView',
|
'AssignRemoveView', 'ConfirmView', 'FormView', 'MultiFormView',
|
||||||
'MultiFormView', 'SingleObjectCreateView', 'SingleObjectDeleteView',
|
'MultipleObjectConfirmActionView', 'MultipleObjectFormActionView',
|
||||||
|
'SingleObjectCreateView', 'SingleObjectDeleteView',
|
||||||
'SingleObjectDetailView', 'SingleObjectEditView', 'SingleObjectListView',
|
'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
|
This view will present a form and upon receiving a POST request will
|
||||||
perform an action on an object or queryset
|
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'
|
template_name = 'appearance/generic_form.html'
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
self.view_action(form=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):
|
class MultipleObjectConfirmActionView(ObjectActionMixin, MultipleObjectMixin, ViewPermissionCheckMixin, ExtraContextMixin, RedirectionMixin, TemplateView):
|
||||||
result = super(ActionView, self).get_form_kwargs()
|
template_name = 'appearance/generic_confirm.html'
|
||||||
result.update(self.get_form_extra_kwargs())
|
|
||||||
return result
|
|
||||||
|
|
||||||
def get_pk_list(self):
|
def post(self, request, *args, **kwargs):
|
||||||
result = self.request.GET.get(
|
self.view_action()
|
||||||
'id_list', self.request.POST.get('id_list')
|
return HttpResponseRedirect(self.get_success_url())
|
||||||
)
|
|
||||||
|
|
||||||
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)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class AssignRemoveView(ExtraContextMixin, ViewPermissionCheckMixin, ObjectPermissionCheckMixin, TemplateView):
|
class AssignRemoveView(ExtraContextMixin, ViewPermissionCheckMixin, ObjectPermissionCheckMixin, TemplateView):
|
||||||
|
|||||||
@@ -1,17 +1,21 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.apps import apps
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
|
from django.db.models.query import QuerySet
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.utils.translation import ungettext, ugettext_lazy as _
|
from django.utils.translation import ungettext, ugettext_lazy as _
|
||||||
|
|
||||||
from permissions import Permission
|
from permissions import Permission
|
||||||
|
|
||||||
|
from acls.models import AccessControlList
|
||||||
|
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'DeleteExtraDataMixin', 'ExtraContextMixin',
|
'DeleteExtraDataMixin', 'ExtraContextMixin', 'FormExtraKwargsMixin',
|
||||||
|
'MultipleObjectMixin', 'ObjectActionMixin',
|
||||||
'ObjectListPermissionFilterMixin', 'ObjectNameMixin',
|
'ObjectListPermissionFilterMixin', 'ObjectNameMixin',
|
||||||
'ObjectPermissionCheckMixin', 'RedirectionMixin',
|
'ObjectPermissionCheckMixin', 'RedirectionMixin',
|
||||||
'ViewPermissionCheckMixin'
|
'ViewPermissionCheckMixin'
|
||||||
@@ -30,7 +34,27 @@ class DeleteExtraDataMixin(object):
|
|||||||
return HttpResponseRedirect(success_url)
|
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):
|
class ExtraContextMixin(object):
|
||||||
|
"""
|
||||||
|
Mixin that allows views to pass extra context to the template
|
||||||
|
"""
|
||||||
|
|
||||||
extra_context = {}
|
extra_context = {}
|
||||||
|
|
||||||
def get_extra_context(self):
|
def get_extra_context(self):
|
||||||
@@ -44,8 +68,8 @@ class ExtraContextMixin(object):
|
|||||||
|
|
||||||
class MultipleInstanceActionMixin(object):
|
class MultipleInstanceActionMixin(object):
|
||||||
model = None
|
model = None
|
||||||
success_message = 'Operation performed on %(count)d object'
|
success_message = _('Operation performed on %(count)d object')
|
||||||
success_message_plural = 'Operation performed on %(count)d objects'
|
success_message_plural = _('Operation performed on %(count)d objects')
|
||||||
|
|
||||||
def get_pk_list(self):
|
def get_pk_list(self):
|
||||||
return self.request.GET.get(
|
return self.request.GET.get(
|
||||||
@@ -82,14 +106,108 @@ class MultipleInstanceActionMixin(object):
|
|||||||
return HttpResponseRedirect(self.get_success_url())
|
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):
|
class ObjectListPermissionFilterMixin(object):
|
||||||
object_permission = None
|
object_permission = None
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
AccessControlList = apps.get_model(
|
|
||||||
app_label='acls', model_name='AccessControlList'
|
|
||||||
)
|
|
||||||
|
|
||||||
queryset = super(ObjectListPermissionFilterMixin, self).get_queryset()
|
queryset = super(ObjectListPermissionFilterMixin, self).get_queryset()
|
||||||
|
|
||||||
if self.object_permission:
|
if self.object_permission:
|
||||||
@@ -123,10 +241,6 @@ class ObjectPermissionCheckMixin(object):
|
|||||||
return self.get_object()
|
return self.get_object()
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
AccessControlList = apps.get_model(
|
|
||||||
app_label='acls', model_name='AccessControlList'
|
|
||||||
)
|
|
||||||
|
|
||||||
if self.object_permission:
|
if self.object_permission:
|
||||||
AccessControlList.objects.check_access(
|
AccessControlList.objects.check_access(
|
||||||
permissions=self.object_permission, user=request.user,
|
permissions=self.object_permission, user=request.user,
|
||||||
|
|||||||
Reference in New Issue
Block a user