Files
mayan-edms/mayan/apps/cabinets/serializers.py
Roberto Rosario 68a2b25f0d Disable select_for_update when checking the uniqueness of a
cabinet if the database backend is Oracle.
GitHub issue #258. Thanks to @simeon-walker for the report.

Signed-off-by: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>
2017-07-22 04:58:19 -04:00

200 lines
6.6 KiB
Python

from __future__ import unicode_literals
from django.db import connection, transaction
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from rest_framework.reverse import reverse
from rest_framework.settings import api_settings
from rest_framework_recursive.fields import RecursiveField
from documents.models import Document
from documents.serializers import DocumentSerializer
from .models import Cabinet
class CabinetSerializer(serializers.ModelSerializer):
children = RecursiveField(
help_text=_('List of children cabinets.'), many=True, read_only=True
)
documents_count = serializers.SerializerMethodField(
help_text=_('Number of documents on this cabinet level.')
)
full_path = serializers.SerializerMethodField(
help_text=_(
'The name of this cabinet level appended to the names of its '
'ancestors.'
)
)
documents_url = serializers.HyperlinkedIdentityField(
help_text=_(
'URL of the API endpoint showing the list documents inside this '
'cabinet.'
), view_name='rest_api:cabinet-document-list'
)
parent_url = serializers.SerializerMethodField()
class Meta:
extra_kwargs = {
'url': {'view_name': 'rest_api:cabinet-detail'},
}
fields = (
'children', 'documents_count', 'documents_url', 'full_path', 'id',
'label', 'parent', 'parent_url', 'url'
)
model = Cabinet
def get_documents_count(self, obj):
return obj.get_document_count(user=self.context['request'].user)
def get_full_path(self, obj):
return obj.get_full_path()
def get_parent_url(self, obj):
if obj.parent:
return reverse(
'rest_api:cabinet-detail', args=(obj.parent.pk,),
format=self.context['format'],
request=self.context.get('request')
)
else:
return ''
class WritableCabinetSerializer(serializers.ModelSerializer):
documents_pk_list = serializers.CharField(
help_text=_(
'Comma separated list of document primary keys to add to this '
'cabinet.'
), required=False
)
# This is here because parent is optional in the model but the serializer
# sets it as required.
parent = serializers.PrimaryKeyRelatedField(
allow_null=True, queryset=Cabinet.objects.all(), required=False
)
class Meta:
fields = ('documents_pk_list', 'label', 'id', 'parent')
model = Cabinet
def _add_documents(self, documents_pk_list, instance):
instance.documents.add(
*Document.objects.filter(pk__in=documents_pk_list.split(','))
)
def create(self, validated_data):
documents_pk_list = validated_data.pop('documents_pk_list', '')
instance = super(WritableCabinetSerializer, self).create(validated_data)
if documents_pk_list:
self._add_documents(
documents_pk_list=documents_pk_list, instance=instance
)
return instance
def update(self, instance, validated_data):
documents_pk_list = validated_data.pop('documents_pk_list', '')
instance = super(WritableCabinetSerializer, self).update(
instance, validated_data
)
if documents_pk_list:
instance.documents.clear()
self._add_documents(
documents_pk_list=documents_pk_list, instance=instance
)
return instance
def run_validation(self, data=None):
# Copy data into a new dictionary since data is an immutable type
result = data.copy()
# Add None parent to keep validation from failing.
# This is here because parent is optional in the model but the serializer
# sets it as required.
result.setdefault('parent')
data = super(WritableCabinetSerializer, self).run_validation(result)
# Explicit validation of uniqueness of parent+label as the provided
# unique_together check in Meta is not working for all 100% cases
# when there is a FK in the unique_together tuple
# https://code.djangoproject.com/ticket/1751
with transaction.atomic():
if connection.vendor == 'oracle':
queryset = Cabinet.objects.filter(parent=data['parent'], label=data['label'])
else:
queryset = Cabinet.objects.select_for_update().filter(parent=data['parent'], label=data['label'])
if queryset.exists():
params = {
'model_name': _('Cabinet'),
'field_labels': _('Parent and Label')
}
raise serializers.ValidationError(
{
api_settings.NON_FIELD_ERRORS_KEY: [
_(
'%(model_name)s with this %(field_labels)s '
'already exists.'
) % params
],
},
)
return data
class CabinetDocumentSerializer(DocumentSerializer):
cabinet_document_url = serializers.SerializerMethodField(
help_text=_(
'API URL pointing to a document in relation to the cabinet '
'storing it. This URL is different than the canonical document '
'URL.'
)
)
class Meta(DocumentSerializer.Meta):
fields = DocumentSerializer.Meta.fields + ('cabinet_document_url',)
read_only_fields = DocumentSerializer.Meta.fields
def get_cabinet_document_url(self, instance):
return reverse(
'rest_api:cabinet-document', args=(
self.context['cabinet'].pk, instance.pk
), request=self.context['request'], format=self.context['format']
)
class NewCabinetDocumentSerializer(serializers.Serializer):
documents_pk_list = serializers.CharField(
help_text=_(
'Comma separated list of document primary keys to add to this '
'cabinet.'
)
)
def _add_documents(self, documents_pk_list, instance):
instance.documents.add(
*Document.objects.filter(pk__in=documents_pk_list.split(','))
)
def create(self, validated_data):
documents_pk_list = validated_data['documents_pk_list']
if documents_pk_list:
self._add_documents(
documents_pk_list=documents_pk_list,
instance=validated_data['cabinet']
)
return {'documents_pk_list': documents_pk_list}