Save nested fields.
authorymh <ymh.work@gmail.com>
Mon, 09 Sep 2013 01:48:26 +0200
changeset 48 e2ccb0093452
parent 47 b07f8d11f2b8
child 49 fcfa68f39f6b
Save nested fields.
src/p4l/api/serializers.py
src/p4l/settings.py
--- a/src/p4l/api/serializers.py	Sat Sep 07 14:41:20 2013 +0200
+++ b/src/p4l/api/serializers.py	Mon Sep 09 01:48:26 2013 +0200
@@ -5,11 +5,12 @@
 @author: ymh
 '''
 from django.core.exceptions import ValidationError
-from p4l.models import (Record, Title, Issn, Isbn, DocumentCode, Abstract,
-    AddedTitle, TitleMainDocument, Imprint, Collation, VolumeIssue, Periodical,
-    Meeting, SubjectMeeting, Serie, Url)
+from p4l.models import Record
 from rest_framework import serializers
 import logging
+from rest_framework.serializers import NestedValidationError
+import copy
+from django.db.models.fields.related import ForeignKey
 
 logger = logging.getLogger(__name__)
 
@@ -32,84 +33,87 @@
             raise ValidationError(msg)
 
 
-class BaseTitleSerializer(serializers.ModelSerializer):
-    class Meta:
-        fields = ('title', 'lang')
+class P4lModelSerializer(serializers.ModelSerializer):
+    
     
-class TitleSerializer(BaseTitleSerializer):    
-    class Meta(BaseTitleSerializer.Meta):
-        model = Title
+    def get_nested_field(self, model_field, related_model, to_many):
+        field_exclude = ()
+        if model_field is None:
+            fk = [f.name for f in related_model._meta.fields if (isinstance(f, ForeignKey) and f.rel.to == Record)][0]
+            field_exclude = ('id', fk)
+        class NestedModelSerializer(P4lModelSerializer):
+            class Meta:
+                model = related_model
+                depth = self.opts.depth - 1
+                exclude = field_exclude
 
-class AddedTitleSerializer(BaseTitleSerializer):    
-    class Meta(BaseTitleSerializer.Meta):
-        model = AddedTitle
-
-class TitleMainDocumentSerializer(BaseTitleSerializer):    
-    class Meta(BaseTitleSerializer.Meta):
-        model = TitleMainDocument
+        return NestedModelSerializer(many=to_many)
 
-class IssnSerializer(serializers.ModelSerializer):
-    class Meta:
-        model = Issn
-        fields = ('issn', 'lang')
-
-class IsbnSerializer(serializers.ModelSerializer):
-    class Meta:
-        model = Isbn
-        fields = ('isbn', 'lang')
-
-class DocumentCodeSerializer(serializers.ModelSerializer):
-    class Meta:
-        model = DocumentCode
-        fields = ('documentCode', 'lang')
+        
+    def field_from_native(self, data, files, field_name, into):
+        """
+        Override default so that the serializer can be used as a writable
+        nested field across relationships.
+        """        
+        if self.read_only:
+            return
         
-class AbstractSerializer(serializers.ModelSerializer):
-    class Meta:
-        model = Abstract
-        fields = ('abstract', 'lang')
+        try:
+            value = data[field_name]
+        except KeyError:
+            if self.default is not None and not self.partial:
+                # Note: partial updates shouldn't set defaults
+                value = copy.deepcopy(self.default)
+            else:
+                if self.required:
+                    raise ValidationError(self.error_messages['required'])
+                return
 
-class ImprintSerializer(serializers.ModelSerializer):
-    class Meta:
-        model = Imprint
-        fields = ('imprintCity', 'publisher', 'imprintDate', 'lang')
-
-class CollationSerializer(serializers.ModelSerializer):
-    class Meta:
-        model = Collation
-        fields = ('collation', 'lang')
-
-class VolumeIssueSerializer(serializers.ModelSerializer):
-    class Meta:
-        model = VolumeIssue
-        fields = ('volume', 'number', 'lang')
-
-class PeriodicalSerializer(serializers.ModelSerializer):
-    class Meta:
-        model = Periodical
-        fields = ('label', 'lang')
+        # Set the serializer object if it exists
+        obj = getattr(self.parent.object, field_name) if self.parent.object else None
 
-class MeetingSerializer(serializers.ModelSerializer):
-    class Meta:
-        model = Meeting
-        fields = ('label', 'meetingNumber', 'meetingPlace', 'meetingDate', 'meetingYear', 'lang')
-
-class SubjectMeetingSerializer(serializers.ModelSerializer):
-    class Meta:
-        model = SubjectMeeting
-        fields = ('label', 'meetingNumber', 'meetingPlace', 'meetingDate', 'meetingYear')
+        if self.source == '*':
+            if value:
+                into.update(value)
+        else:
+            if value in (None, ''):
+                into[(self.source or field_name)] = None
+            elif self.many and hasattr(value, '__iter__'):
+                obj.all().delete()
+                nested_items = []
+                for val in value:
+                    kwargs = {
+                        'instance': None,
+                        'data': val,
+                        'context': self.context,
+                        'partial': self.partial,
+                        'many': False
+                    }
+                    serializer = self.__class__(**kwargs)
+                    nested_items.append(serializer.from_native(val, files))
+                into[self.source or field_name] = nested_items
+            else:
+                kwargs = {
+                    'instance': obj,
+                    'data': value,
+                    'context': self.context,
+                    'partial': self.partial,
+                    'many': self.many
+                }
+                serializer = self.__class__(**kwargs)
 
-class SerieSerializer(serializers.ModelSerializer):
-    class Meta:
-        model = Serie
-        fields = ('title', 'volume', 'lang')
-
-class UrlSerializer(serializers.ModelSerializer):
-    class Meta:
-        model = Url
-        fields = ('address', 'display', 'accessLevel')
+                if serializer.is_valid():
+                    into[self.source or field_name] = serializer.object
+                else:
+                    # Propagate errors up to our parent
+                    raise NestedValidationError(serializer.errors)
 
 
-class RecordSerializer(serializers.ModelSerializer):
+
+
+
+#class RecordSerializer(serializers.ModelSerializer):
+class RecordSerializer(P4lModelSerializer):
     '''
     Serializer for record
     '''
@@ -121,23 +125,6 @@
     projectNames = ThesaurusSerializer(many=True, slug_field='uri')
     subjectCorporateBodies = ThesaurusSerializer(many=True, slug_field='uri') 
     corporateAuthors = ThesaurusSerializer(many=True, slug_field='uri')
-#    titles = TitleSerializer(many=True, read_only=False)
-#    addedTitles = AddedTitleSerializer(many=True, read_only=False)
-#    issns = IssnSerializer(many=True, read_only=False)
-#    isbns = IsbnSerializer(many=True, read_only=False)
-#    documentCodes = DocumentCodeSerializer(many=True, read_only=False)
-#    abstracts = AbstractSerializer(many=True, read_only=False)
-#    titlesMainDocument = TitleMainDocumentSerializer(many=True, read_only=False)
-#    imprints = ImprintSerializer(many=True, read_only=False)
-#    collations = CollationSerializer(many=True, read_only=False)    
-#    volumeIssues = VolumeIssueSerializer(many=True, read_only=False)
-#    periodicals = PeriodicalSerializer(many=True, read_only=False)
-#    meetings = MeetingSerializer(many=True, read_only=False)
-#    subjectMeetings = SubjectMeetingSerializer(many=True, read_only=False)
-#    series = SerieSerializer(many=True, read_only=False)
-#    authors = serializers.SlugRelatedField(many=True, read_only=False, slug_field="name")
-#    subjectPersons = serializers.SlugRelatedField(many=True, read_only=False, slug_field="name")
-#    urls = UrlSerializer(many=True, read_only=False)
 
     class Meta:
         model = Record
@@ -146,16 +133,10 @@
         fields = ("identifier", "uri", "subjects", "notes", "otherLanguages",
                   "language", "editionStatement", "recordType", "isDocumentPart",
                   "isMultilingual", "themes", "countries", "projectNames", 
-                  "subjectCorporateBodies", "corporateAuthors")
-#         fields = (
-#                       "editionStatement", "recordType","isDocumentPart",
-#                   "isMultilingual","subjects", "themes", "countries",
-#                   "projectNames", "subjectCorporateBodies", "corporateAuthors",
-#                   "titles", "issns", "isbns", "documentCodes", "abstracts",
-#                   "addedTitles", "titlesMainDocument", "imprints",
-#                   "collations", "volumeIssues", "periodicals", "meetings",
-#                   "subjectMeetings", "series", "authors", "subjectPersons",
-#                   "urls")        
-
+                  "subjectCorporateBodies", "corporateAuthors", "imprints",
+                  "titles", "addedTitles", "issns", "isbns", "documentCodes",
+                  "abstracts", "titlesMainDocument", "collations", "volumeIssues",
+                  "periodicals", "meetings", "subjectMeetings", "series",
+                  "authors", "subjectPersons", "urls")
 
     
--- a/src/p4l/settings.py	Sat Sep 07 14:41:20 2013 +0200
+++ b/src/p4l/settings.py	Mon Sep 09 01:48:26 2013 +0200
@@ -133,6 +133,7 @@
     'django.contrib.messages',
     'django.contrib.staticfiles',
     'django.contrib.admin',
+    'django_extensions',
     'south',
     'rest_framework',
     'p4l'