src/p4l/api/serializers.py
author cavaliet
Mon, 16 Sep 2013 16:18:30 +0200
changeset 93 c675183a9325
parent 48 e2ccb0093452
child 98 7b6ca4ca3f67
permissions -rw-r--r--
new record
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
16
19fe06edb58d Add api for records
ymh <ymh.work@gmail.com>
parents:
diff changeset
     1
# -*- coding: utf-8 -*-
19fe06edb58d Add api for records
ymh <ymh.work@gmail.com>
parents:
diff changeset
     2
'''
19fe06edb58d Add api for records
ymh <ymh.work@gmail.com>
parents:
diff changeset
     3
Created on Sep 2, 2013
19fe06edb58d Add api for records
ymh <ymh.work@gmail.com>
parents:
diff changeset
     4
19fe06edb58d Add api for records
ymh <ymh.work@gmail.com>
parents:
diff changeset
     5
@author: ymh
19fe06edb58d Add api for records
ymh <ymh.work@gmail.com>
parents:
diff changeset
     6
'''
47
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
     7
from django.core.exceptions import ValidationError
48
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
     8
from p4l.models import Record
16
19fe06edb58d Add api for records
ymh <ymh.work@gmail.com>
parents:
diff changeset
     9
from rest_framework import serializers
47
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
    10
import logging
48
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    11
from rest_framework.serializers import NestedValidationError
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    12
import copy
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    13
from django.db.models.fields.related import ForeignKey
47
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
    14
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
    15
logger = logging.getLogger(__name__)
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
    16
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
    17
class ThesaurusSerializer(serializers.SlugRelatedField):
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
    18
    
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
    19
    def __init__(self, *args, **kwargs):
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
    20
        kwargs.update({                       
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
    21
            'read_only': False,
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
    22
        })
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
    23
        serializers.SlugRelatedField.__init__(self, *args, **kwargs)
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
    24
        
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
    25
    def from_native(self, data):
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
    26
        if self.queryset is None:
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
    27
            raise Exception('Writable related fields must include a `queryset` argument')
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
    28
        try:
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
    29
            res, _ = self.queryset.get_or_create(**{self.slug_field: data})
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
    30
            return res
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
    31
        except (TypeError, ValueError):
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
    32
            msg = self.error_messages['invalid']
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
    33
            raise ValidationError(msg)
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
    34
16
19fe06edb58d Add api for records
ymh <ymh.work@gmail.com>
parents:
diff changeset
    35
48
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    36
class P4lModelSerializer(serializers.ModelSerializer):
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    37
    
16
19fe06edb58d Add api for records
ymh <ymh.work@gmail.com>
parents:
diff changeset
    38
    
48
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    39
    def get_nested_field(self, model_field, related_model, to_many):
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    40
        field_exclude = ()
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    41
        if model_field is None:
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    42
            fk = [f.name for f in related_model._meta.fields if (isinstance(f, ForeignKey) and f.rel.to == Record)][0]
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    43
            field_exclude = ('id', fk)
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    44
        class NestedModelSerializer(P4lModelSerializer):
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    45
            class Meta:
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    46
                model = related_model
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    47
                depth = self.opts.depth - 1
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    48
                exclude = field_exclude
16
19fe06edb58d Add api for records
ymh <ymh.work@gmail.com>
parents:
diff changeset
    49
48
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    50
        return NestedModelSerializer(many=to_many)
16
19fe06edb58d Add api for records
ymh <ymh.work@gmail.com>
parents:
diff changeset
    51
48
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    52
        
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    53
    def field_from_native(self, data, files, field_name, into):
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    54
        """
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    55
        Override default so that the serializer can be used as a writable
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    56
        nested field across relationships.
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    57
        """        
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    58
        if self.read_only:
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    59
            return
16
19fe06edb58d Add api for records
ymh <ymh.work@gmail.com>
parents:
diff changeset
    60
        
48
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    61
        try:
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    62
            value = data[field_name]
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    63
        except KeyError:
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    64
            if self.default is not None and not self.partial:
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    65
                # Note: partial updates shouldn't set defaults
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    66
                value = copy.deepcopy(self.default)
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    67
            else:
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    68
                if self.required:
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    69
                    raise ValidationError(self.error_messages['required'])
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    70
                return
16
19fe06edb58d Add api for records
ymh <ymh.work@gmail.com>
parents:
diff changeset
    71
48
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    72
        # Set the serializer object if it exists
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    73
        obj = getattr(self.parent.object, field_name) if self.parent.object else None
16
19fe06edb58d Add api for records
ymh <ymh.work@gmail.com>
parents:
diff changeset
    74
48
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    75
        if self.source == '*':
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    76
            if value:
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    77
                into.update(value)
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    78
        else:
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    79
            if value in (None, ''):
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    80
                into[(self.source or field_name)] = None
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    81
            elif self.many and hasattr(value, '__iter__'):
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    82
                obj.all().delete()
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    83
                nested_items = []
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    84
                for val in value:
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    85
                    kwargs = {
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    86
                        'instance': None,
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    87
                        'data': val,
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    88
                        'context': self.context,
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    89
                        'partial': self.partial,
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    90
                        'many': False
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    91
                    }
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    92
                    serializer = self.__class__(**kwargs)
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    93
                    nested_items.append(serializer.from_native(val, files))
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    94
                into[self.source or field_name] = nested_items
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    95
            else:
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    96
                kwargs = {
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    97
                    'instance': obj,
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    98
                    'data': value,
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
    99
                    'context': self.context,
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
   100
                    'partial': self.partial,
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
   101
                    'many': self.many
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
   102
                }
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
   103
                serializer = self.__class__(**kwargs)
16
19fe06edb58d Add api for records
ymh <ymh.work@gmail.com>
parents:
diff changeset
   104
48
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
   105
                if serializer.is_valid():
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
   106
                    into[self.source or field_name] = serializer.object
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
   107
                else:
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
   108
                    # Propagate errors up to our parent
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
   109
                    raise NestedValidationError(serializer.errors)
16
19fe06edb58d Add api for records
ymh <ymh.work@gmail.com>
parents:
diff changeset
   110
47
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
   111
48
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
   112
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
   113
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
   114
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
   115
#class RecordSerializer(serializers.ModelSerializer):
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
   116
class RecordSerializer(P4lModelSerializer):
16
19fe06edb58d Add api for records
ymh <ymh.work@gmail.com>
parents:
diff changeset
   117
    '''
19fe06edb58d Add api for records
ymh <ymh.work@gmail.com>
parents:
diff changeset
   118
    Serializer for record
19fe06edb58d Add api for records
ymh <ymh.work@gmail.com>
parents:
diff changeset
   119
    '''
93
c675183a9325 new record
cavaliet
parents: 48
diff changeset
   120
    language = ThesaurusSerializer(many=False, required=False, slug_field='uri') 
47
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
   121
    otherLanguages = ThesaurusSerializer(many=True, slug_field='uri')
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
   122
    subjects = ThesaurusSerializer(many=True, slug_field='uri')
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
   123
    themes = ThesaurusSerializer(many=True, slug_field='uri')
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
   124
    countries = ThesaurusSerializer(many=True, slug_field='uri')
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
   125
    projectNames = ThesaurusSerializer(many=True, slug_field='uri')
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
   126
    subjectCorporateBodies = ThesaurusSerializer(many=True, slug_field='uri') 
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
   127
    corporateAuthors = ThesaurusSerializer(many=True, slug_field='uri')
16
19fe06edb58d Add api for records
ymh <ymh.work@gmail.com>
parents:
diff changeset
   128
19fe06edb58d Add api for records
ymh <ymh.work@gmail.com>
parents:
diff changeset
   129
    class Meta:
19fe06edb58d Add api for records
ymh <ymh.work@gmail.com>
parents:
diff changeset
   130
        model = Record
19fe06edb58d Add api for records
ymh <ymh.work@gmail.com>
parents:
diff changeset
   131
        depth = 1
19fe06edb58d Add api for records
ymh <ymh.work@gmail.com>
parents:
diff changeset
   132
        read_only_fields = ('identifier', 'uri')
47
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
   133
        fields = ("identifier", "uri", "subjects", "notes", "otherLanguages",
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
   134
                  "language", "editionStatement", "recordType", "isDocumentPart",
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
   135
                  "isMultilingual", "themes", "countries", "projectNames", 
48
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
   136
                  "subjectCorporateBodies", "corporateAuthors", "imprints",
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
   137
                  "titles", "addedTitles", "issns", "isbns", "documentCodes",
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
   138
                  "abstracts", "titlesMainDocument", "collations", "volumeIssues",
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
   139
                  "periodicals", "meetings", "subjectMeetings", "series",
e2ccb0093452 Save nested fields.
ymh <ymh.work@gmail.com>
parents: 47
diff changeset
   140
                  "authors", "subjectPersons", "urls")
16
19fe06edb58d Add api for records
ymh <ymh.work@gmail.com>
parents:
diff changeset
   141
47
b07f8d11f2b8 Update angular.
ymh <ymh.work@gmail.com>
parents: 16
diff changeset
   142