Improve REST mixins and add a new one
Add type casting to ExternalObjectListSerializerMixin via the external_object_list_pk_type option. Add an ExternalObjectSerializeMixin for related objects. Signed-off-by: Roberto Rosario <Roberto.Rosario@mayan-edms.com>
This commit is contained in:
@@ -2,6 +2,7 @@ from __future__ import absolute_import, unicode_literals
|
|||||||
|
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
|
|
||||||
|
from rest_framework.exceptions import ValidationError
|
||||||
from rest_framework.settings import api_settings
|
from rest_framework.settings import api_settings
|
||||||
|
|
||||||
from mayan.apps.acls.models import AccessControlList
|
from mayan.apps.acls.models import AccessControlList
|
||||||
@@ -16,6 +17,7 @@ class ExternalObjectListSerializerMixin(object):
|
|||||||
external_object_list_queryset
|
external_object_list_queryset
|
||||||
external_object_list_pk_field
|
external_object_list_pk_field
|
||||||
external_object_list_pk_list_field
|
external_object_list_pk_list_field
|
||||||
|
external_object_list_pk_type
|
||||||
|
|
||||||
The source queryset can also be provided overriding the
|
The source queryset can also be provided overriding the
|
||||||
.get_external_object_list_queryset() method.
|
.get_external_object_list_queryset() method.
|
||||||
@@ -23,14 +25,24 @@ class ExternalObjectListSerializerMixin(object):
|
|||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(ExternalObjectListSerializerMixin, self).__init__(*args, **kwargs)
|
super(ExternalObjectListSerializerMixin, self).__init__(*args, **kwargs)
|
||||||
self.external_object_list_options = getattr(self, 'Meta', None)
|
self.external_object_list_options = getattr(self, 'Meta', None)
|
||||||
|
self.external_object_list_options_defaults = {
|
||||||
|
'external_object_list_pk_type': int
|
||||||
|
}
|
||||||
|
|
||||||
|
def filter_queryset(self, id_list, queryset):
|
||||||
|
"""
|
||||||
|
Allow customizing the final filtering, used for object lists that are
|
||||||
|
not a queryset like the Permission class.
|
||||||
|
"""
|
||||||
|
return queryset.filter(pk__in=id_list)
|
||||||
|
|
||||||
def get_external_object_list(self):
|
def get_external_object_list(self):
|
||||||
queryset = self.get_external_object_list_queryset()
|
queryset = self.get_external_object_list_queryset()
|
||||||
|
|
||||||
if self.Meta.external_object_list_permission:
|
permission = self.get_external_object_list_option('permission')
|
||||||
|
if permission:
|
||||||
queryset = AccessControlList.objects.restrict_queryset(
|
queryset = AccessControlList.objects.restrict_queryset(
|
||||||
permission=self.Meta.external_object_list_permission,
|
permission=permission, queryset=queryset,
|
||||||
queryset=queryset,
|
|
||||||
user=self.context['request'].user
|
user=self.context['request'].user
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -40,7 +52,7 @@ class ExternalObjectListSerializerMixin(object):
|
|||||||
if not pk_field and not pk_list_field:
|
if not pk_field and not pk_list_field:
|
||||||
raise ImproperlyConfigured(
|
raise ImproperlyConfigured(
|
||||||
'ExternalObjectListSerializerMixin requires a '
|
'ExternalObjectListSerializerMixin requires a '
|
||||||
'external_object_list_pk_field a '
|
'external_object_list_pk_field or a'
|
||||||
'external_object_list_pk_list_field.'
|
'external_object_list_pk_list_field.'
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -61,12 +73,33 @@ class ExternalObjectListSerializerMixin(object):
|
|||||||
else:
|
else:
|
||||||
id_list = ()
|
id_list = ()
|
||||||
|
|
||||||
return queryset.filter(pk__in=id_list)
|
pk_type = self.get_external_object_list_option('pk_type')
|
||||||
|
|
||||||
|
if pk_type:
|
||||||
|
result = []
|
||||||
|
|
||||||
|
for pk in id_list:
|
||||||
|
try:
|
||||||
|
result.append(pk_type(pk))
|
||||||
|
except Exception as exception:
|
||||||
|
raise ValidationError(
|
||||||
|
{
|
||||||
|
api_settings.NON_FIELD_ERRORS_KEY: [
|
||||||
|
'Value "{}" is not of a valid type; {}'.format(pk, exception)
|
||||||
|
]
|
||||||
|
}, code='invalid'
|
||||||
|
)
|
||||||
|
|
||||||
|
id_list = result
|
||||||
|
|
||||||
|
return self.filter_queryset(id_list=id_list, queryset=queryset)
|
||||||
|
|
||||||
def get_external_object_list_option(self, option_name):
|
def get_external_object_list_option(self, option_name):
|
||||||
|
full_option_name = 'external_object_list_{}'.format(option_name)
|
||||||
|
|
||||||
return getattr(
|
return getattr(
|
||||||
self.external_object_list_options, 'external_object_list_{}'.format(option_name),
|
self.external_object_list_options, full_option_name,
|
||||||
None
|
self.external_object_list_options_defaults.get(full_option_name)
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_external_object_list_queryset(self):
|
def get_external_object_list_queryset(self):
|
||||||
@@ -86,6 +119,82 @@ class ExternalObjectListSerializerMixin(object):
|
|||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
|
class ExternalObjectSerializerMixin(object):
|
||||||
|
"""
|
||||||
|
Mixin to allow serializers to get a restricted object with minimal code.
|
||||||
|
This mixin adds the follow class Meta options to a serializer:
|
||||||
|
external_object_model
|
||||||
|
external_object_permission
|
||||||
|
external_object_queryset
|
||||||
|
external_object_pk_field
|
||||||
|
The source queryset can also be provided overriding the
|
||||||
|
.get_external_object_queryset() method.
|
||||||
|
"""
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(ExternalObjectSerializerMixin, self).__init__(*args, **kwargs)
|
||||||
|
self.external_object_options = getattr(self, 'Meta', None)
|
||||||
|
|
||||||
|
def get_external_object(self):
|
||||||
|
queryset = self.get_external_object_queryset()
|
||||||
|
|
||||||
|
permission = self.get_external_object_permission()
|
||||||
|
if permission:
|
||||||
|
queryset = AccessControlList.objects.restrict_queryset(
|
||||||
|
permission=permission, queryset=queryset,
|
||||||
|
user=self.context['request'].user
|
||||||
|
)
|
||||||
|
|
||||||
|
pk_field = self.get_external_object_option('pk_field')
|
||||||
|
|
||||||
|
if not pk_field:
|
||||||
|
raise ImproperlyConfigured(
|
||||||
|
'ExternalObjectSerializerMixin requires a '
|
||||||
|
'external_object_pk_field.'
|
||||||
|
)
|
||||||
|
|
||||||
|
if pk_field:
|
||||||
|
pk_field_value = self.validated_data.get(pk_field)
|
||||||
|
else:
|
||||||
|
pk_field_value = None
|
||||||
|
|
||||||
|
if pk_field_value:
|
||||||
|
try:
|
||||||
|
return queryset.get(pk=pk_field_value)
|
||||||
|
except Exception as exception:
|
||||||
|
raise ValidationError(
|
||||||
|
{
|
||||||
|
pk_field: [exception]
|
||||||
|
}, code='invalid'
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_external_object_option(self, option_name):
|
||||||
|
full_option_name = 'external_object_{}'.format(option_name)
|
||||||
|
|
||||||
|
return getattr(
|
||||||
|
self.external_object_options, full_option_name,
|
||||||
|
None
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_external_object_permission(self):
|
||||||
|
return self.get_external_object_option('permission')
|
||||||
|
|
||||||
|
def get_external_object_queryset(self):
|
||||||
|
model = self.get_external_object_option('model')
|
||||||
|
queryset = self.get_external_object_option('queryset')
|
||||||
|
|
||||||
|
if model:
|
||||||
|
queryset = model._meta.default_manager.all()
|
||||||
|
elif queryset:
|
||||||
|
return queryset
|
||||||
|
else:
|
||||||
|
raise ImproperlyConfigured(
|
||||||
|
'ExternalObjectListSerializerMixin requires a '
|
||||||
|
'external_object_model or a external_object_queryset.'
|
||||||
|
)
|
||||||
|
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
class SuccessHeadersMixin(object):
|
class SuccessHeadersMixin(object):
|
||||||
def get_success_headers(self, data):
|
def get_success_headers(self, data):
|
||||||
try:
|
try:
|
||||||
|
|||||||
Reference in New Issue
Block a user