Add support for single or multiple objects modes

View that use the MultipleObjectMixin can now fully operate
as single object or multiple object views.

Add the self.view_mode_single and self.view_mode_multiple flags.

Add support for single, singular and plural titles and success
messages via:

success_message_single, success_message_singular,
sucess_message_plural, title_single, title_singular and
title_plural class attributes.

Insert object_list and object as attributes of the view class
to avoid calling the queryset again.

Signed-off-by: Roberto Rosario <Roberto.Rosario@mayan-edms.com>
This commit is contained in:
Roberto Rosario
2019-02-12 18:01:14 -04:00
parent 23b1375289
commit 8589004173
2 changed files with 79 additions and 39 deletions

View File

@@ -251,32 +251,6 @@ class MultipleObjectDownloadView(RestrictedQuerysetMixin, MultipleObjectMixin, D
return super(MultipleObjectDownloadView, self).get_queryset()
class SingleObjectDownloadView(RestrictedQuerysetMixin, SingleObjectMixin, DownloadViewBase):
"""
View that provides a .get_object() method to download content from a
single object.
"""
def __init__(self, *args, **kwargs):
result = super(SingleObjectDownloadView, self).__init__(*args, **kwargs)
if self.__class__.mro()[0].get_queryset != SingleObjectDownloadView.get_queryset:
raise ImproperlyConfigured(
'%(cls)s is overloading the get_queryset method. Subclasses '
'should implement the get_source_queryset method instead. ' % {
'cls': self.__class__.__name__
}
)
return result
def get_queryset(self):
try:
return super(SingleObjectDownloadView, self).get_queryset()
except ImproperlyConfigured:
self.queryset = self.get_source_queryset()
return super(SingleObjectDownloadView, self).get_queryset()
class MultiFormView(DjangoFormView):
prefix = None
prefixes = {}
@@ -607,7 +581,7 @@ class AddRemoveView(ExternalObjectMixin, ExtraContextMixin, ViewPermissionCheckM
)
class MultipleObjectFormActionView(ObjectActionMixin, ViewPermissionCheckMixin, RestrictedQuerysetMixin, MultipleObjectMixin, FormExtraKwargsMixin, ExtraContextMixin, RedirectionMixin, DjangoFormView):
class MultipleObjectFormActionView(ExtraContextMixin, ObjectActionMixin, ViewPermissionCheckMixin, RestrictedQuerysetMixin, MultipleObjectMixin, FormExtraKwargsMixin, RedirectionMixin, DjangoFormView):
"""
This view will present a form and upon receiving a POST request will
perform an action on an object or queryset
@@ -639,7 +613,7 @@ class MultipleObjectFormActionView(ObjectActionMixin, ViewPermissionCheckMixin,
return super(MultipleObjectFormActionView, self).get_queryset()
class MultipleObjectConfirmActionView(ObjectActionMixin, ViewPermissionCheckMixin, RestrictedQuerysetMixin, MultipleObjectMixin, ExtraContextMixin, RedirectionMixin, TemplateView):
class MultipleObjectConfirmActionView(ExtraContextMixin, ObjectActionMixin, ViewPermissionCheckMixin, RestrictedQuerysetMixin, MultipleObjectMixin, RedirectionMixin, TemplateView):
template_name = 'appearance/generic_confirm.html'
def __init__(self, *args, **kwargs):
@@ -738,6 +712,32 @@ class SingleObjectCreateView(ObjectNameMixin, ViewPermissionCheckMixin, ExtraCon
return self.error_message_duplicate
class SingleObjectDownloadView(RestrictedQuerysetMixin, SingleObjectMixin, DownloadViewBase):
"""
View that provides a .get_object() method to download content from a
single object.
"""
def __init__(self, *args, **kwargs):
result = super(SingleObjectDownloadView, self).__init__(*args, **kwargs)
if self.__class__.mro()[0].get_queryset != SingleObjectDownloadView.get_queryset:
raise ImproperlyConfigured(
'%(cls)s is overloading the get_queryset method. Subclasses '
'should implement the get_source_queryset method instead. ' % {
'cls': self.__class__.__name__
}
)
return result
def get_queryset(self):
try:
return super(SingleObjectDownloadView, self).get_queryset()
except ImproperlyConfigured:
self.queryset = self.get_source_queryset()
return super(SingleObjectDownloadView, self).get_queryset()
class SingleObjectDynamicFormCreateView(DynamicFormViewMixin, SingleObjectCreateView):
pass

View File

@@ -169,7 +169,7 @@ class MultipleInstanceActionMixin(object):
# MultipleObjectFormActionView or MultipleObjectConfirmActionView
model = None
success_message = _('Operation performed on %(count)d object')
success_message_singular = _('Operation performed on %(count)d object')
success_message_plural = _('Operation performed on %(count)d objects')
def get_pk_list(self):
@@ -217,6 +217,13 @@ class MultipleObjectMixin(SingleObjectMixin):
pk_list_key = 'id_list'
pk_list_separator = PK_LIST_SEPARATOR
def dispatch(self, request, *args, **kwargs):
self.object_list = self.get_object_list()
if self.view_mode_single:
self.object = self.object_list.first()
return super(MultipleObjectMixin, self).dispatch(request=request, *args, **kwargs)
def get(self, request, *args, **kwargs):
"""
Override BaseDetailView.get()
@@ -243,6 +250,9 @@ class MultipleObjectMixin(SingleObjectMixin):
`pk_list' argument in the URLconf, but subclasses can override this
to return any object.
"""
self.view_mode_single = False
self.view_mode_multiple = False
# Use a custom queryset if provided; this is required for subclasses
# like DateDetailView
if queryset is None:
@@ -255,14 +265,17 @@ class MultipleObjectMixin(SingleObjectMixin):
if pk is not None:
queryset = queryset.filter(pk=pk)
self.view_mode_single = True
# 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})
self.view_mode_single = True
if pk_list is not None:
queryset = queryset.filter(pk__in=self.get_pk_list())
self.view_mode_multiple = True
# If none of those are defined, it's an error.
if pk is None and slug is None and pk_list is None:
@@ -305,22 +318,49 @@ class ObjectActionMixin(object):
"""
Mixin that performs an user action to a queryset
"""
error_message = 'Unable to perform operation on object %(instance)s.'
error_message = 'Unable to perform operation on object %(instance)s; %(exception)s.'
post_object_action_url = None
success_message = 'Operation performed on %(count)d object.'
success_message_single = 'Operation performed on %(object)s.'
success_message_singular = 'Operation performed on %(count)d object.'
success_message_plural = 'Operation performed on %(count)d objects.'
title_single = 'Perform operation on %(object)s.'
title_singular = 'Perform operation on %(count)d object.'
title_plural = 'Perform operation on %(count)d objects.'
def get_context_data(self, **kwargs):
context = super(ObjectActionMixin, self).get_context_data(**kwargs)
title = None
if self.view_mode_single:
title = self.title_single % {'object': self.object}
elif self.view_mode_multiple:
title = ungettext(
singular=self.title_singular,
plural=self.title_plural,
number=self.object_list.count()
) % {
'count': self.object_list.count(),
}
context['title'] = title
return context
def get_post_object_action_url(self):
return self.post_object_action_url
def get_success_message(self, count):
return ungettext(
singular=self.success_message,
plural=self.success_message_plural,
number=count
) % {
'count': count,
}
if self.view_mode_single:
return self.success_message_single % {'object': self.object}
if self.view_mode_multiple:
return ungettext(
singular=self.success_message_singular,
plural=self.success_message_plural,
number=count
) % {
'count': count,
}
def object_action(self, instance, form=None):
# User supplied method
@@ -330,7 +370,7 @@ class ObjectActionMixin(object):
self.action_count = 0
self.action_id_list = []
for instance in self.get_object_list():
for instance in self.object_list:
try:
self.object_action(form=form, instance=instance)
except Exception as exception: