src/p4l/mapping/serializers.py
changeset 101 71532a54d1c4
child 126 a345f1a67bf1
equal deleted inserted replaced
89:49fda47ceb16 101:71532a54d1c4
       
     1 # -*- coding: utf-8 -*-
       
     2 '''
       
     3 Created on Sep 19, 2013
       
     4 
       
     5 @author: ymh
       
     6 '''
       
     7 import logging
       
     8 
       
     9 from rdflib.namespace import RDF
       
    10 from rdflib.term import URIRef, Literal, BNode
       
    11 from collections import OrderedDict
       
    12 
       
    13 
       
    14 logger = logging.getLogger(__name__)
       
    15 
       
    16 class BaseSerializer(object):
       
    17     
       
    18     creation_counter = 0
       
    19     
       
    20     def __init__(self, predicate=None, many=False):
       
    21         self.predicate = predicate
       
    22         self.creation_counter = BaseSerializer.creation_counter
       
    23         self.many = many
       
    24         BaseSerializer.creation_counter += 1
       
    25         if self.predicate and not isinstance(self.predicate, URIRef):
       
    26             self.predicate = URIRef(predicate)
       
    27     
       
    28 
       
    29 class FieldSerializer(BaseSerializer):
       
    30         
       
    31     def __init__(self, predicate=None, convert=None, source=None, many=False):
       
    32         super(FieldSerializer, self).__init__(predicate=predicate, many=many)
       
    33         self.convert = convert or (lambda x: Literal(unicode(x)) if x else None)
       
    34         self.source = source
       
    35 
       
    36 
       
    37     def get_rdf_object(self, obj, fieldname):
       
    38         raise NotImplemented()
       
    39         
       
    40     def to_graph(self, subject, obj, fieldname, graph):
       
    41         o = self.get_rdf_object(obj, fieldname)
       
    42         if o:
       
    43             graph.add((subject, self.predicate, o))
       
    44         
       
    45 
       
    46 class SimpleFieldSerializer(FieldSerializer):
       
    47     
       
    48     def __init__(self, predicate=None, convert=None, source=None, lang_field=None):
       
    49         super(SimpleFieldSerializer, self).__init__(predicate=predicate, convert=convert, source=source, many=False)
       
    50         self.lang_field = lang_field
       
    51     
       
    52     def get_rdf_object(self, obj, fieldname):
       
    53         res = self.convert(getattr(obj, self.source or fieldname))
       
    54         if res is None:
       
    55             return
       
    56         if not isinstance(res, Literal):
       
    57             res = Literal(unicode(res))        
       
    58         lang = getattr(obj, self.lang_field, None) if self.lang_field else None
       
    59         
       
    60         return Literal(res.value, lang) if lang else res
       
    61 
       
    62 class BooleanFieldSerializer(SimpleFieldSerializer):
       
    63 
       
    64     def bool_convert(self, value):
       
    65         return (Literal('TRUE') if value else Literal('FALSE')) if value is not None else None
       
    66 
       
    67     def __init__(self, predicate=None, convert=None, source=None, lang_field=None):
       
    68         super(BooleanFieldSerializer, self).__init__( predicate, convert=convert, source=source, lang_field=lang_field)
       
    69         self.convert = lambda x: self.bool_convert(x)
       
    70 
       
    71 
       
    72 class RelatedFieldSerializer(SimpleFieldSerializer):
       
    73         
       
    74     def __init__(self, value_field, predicate=None, convert=None, source=None, many=False, lang_field=None):
       
    75         super(RelatedFieldSerializer, self).__init__(predicate, convert, source, lang_field=lang_field)
       
    76         self.many = many
       
    77         self.value_field = value_field
       
    78 
       
    79     def to_graph(self, subject, obj, fieldname, graph):
       
    80         value = getattr(obj, fieldname, None)
       
    81         if not value:
       
    82             return
       
    83         
       
    84         values_to_add = []
       
    85         if self.many:
       
    86             for related_obj in value.all():
       
    87                 values_to_add.append(self.get_rdf_object(related_obj, self.value_field))
       
    88         else:
       
    89             values_to_add.append(self.get_rdf_object(value, self.value_field))
       
    90         for o in values_to_add:
       
    91             if o:
       
    92                 graph.add((subject, self.predicate, o))
       
    93 
       
    94     
       
    95 
       
    96 # Directly adapted from serializers in rest_framework 
       
    97 def _get_declared_fields(bases, attrs):
       
    98     """
       
    99     Create a list of serializer field instances from the passed in 'attrs',
       
   100     plus any fields on the base classes (in 'bases').
       
   101 
       
   102     Note that all fields from the base classes are used.
       
   103     """
       
   104     fields = [(field_name, attrs.pop(field_name))
       
   105               for field_name, obj in list(attrs.iteritems())
       
   106               if isinstance(obj, BaseSerializer)]
       
   107     fields.sort(key=lambda x: x[1].creation_counter)
       
   108 
       
   109     # If this class is subclassing another Serializer, add that Serializer's
       
   110     # fields.  Note that we loop over the bases in *reverse*. This is necessary
       
   111     # in order to maintain the correct order of fields.
       
   112     for base in bases[::-1]:
       
   113         if hasattr(base, 'base_serializers'):
       
   114             fields = list(base.base_serializers.items()) + fields
       
   115 
       
   116     return OrderedDict(fields)
       
   117 
       
   118 
       
   119 class SerializerMetaclass(type):
       
   120     def __new__(cls, name, bases, attrs):
       
   121         attrs['base_serializers'] = _get_declared_fields(bases, attrs)
       
   122         return super(SerializerMetaclass, cls).__new__(cls, name, bases, attrs)
       
   123 
       
   124 
       
   125 class ModelSerializerOptions(object):
       
   126     
       
   127     def __init__(self, meta):
       
   128         self.type = getattr(meta, 'type', None)
       
   129         if self.type and not isinstance(self.type, URIRef):
       
   130             self.type = URIRef(self.type)
       
   131         self.uri_fieldname = getattr(meta, 'uri_fieldname', None)
       
   132 
       
   133 class ModelSerializer(BaseSerializer):
       
   134     
       
   135     __metaclass__ =  SerializerMetaclass
       
   136       
       
   137     class Meta(object):
       
   138         pass
       
   139 
       
   140     def get_serializers(self):
       
   141         return []
       
   142         
       
   143     def get_uri(self, obj):
       
   144         uri = None
       
   145         if self.opts.uri_fieldname:
       
   146             uri = getattr(obj, self.opts.uri_fieldname, None)            
       
   147         return URIRef(uri) if uri else None
       
   148     
       
   149     def object_to_graph(self, subject, uri, obj, graph):
       
   150         
       
   151         if self.predicate:
       
   152             graph.add((subject, self.predicate, uri))
       
   153         
       
   154         for serializer_fieldname, field_serializer in self.base_serializers.iteritems():
       
   155             field_serializer.to_graph(uri, obj, serializer_fieldname, graph)
       
   156 
       
   157     
       
   158     def to_graph(self, subject, obj, fieldname, graph):        
       
   159 
       
   160         uri = self.get_uri(obj)
       
   161         if self.opts.type:
       
   162             graph.add((uri, RDF.type, self.opts.type))
       
   163             
       
   164         obj_to_add = []
       
   165         if fieldname:
       
   166             field_value = getattr(obj, fieldname, None)
       
   167             if field_value:
       
   168                 if self.many:
       
   169                     obj_to_add = [(nested_obj, BNode()) for nested_obj in field_value.all()]
       
   170                 else:
       
   171                     obj_to_add = [(field_value, BNode())]
       
   172         else:
       
   173             obj_to_add = [(obj, uri)]
       
   174         
       
   175         for nested_obj, nested_uri in obj_to_add:
       
   176             self.object_to_graph( subject, nested_uri, nested_obj, graph)
       
   177             
       
   178     
       
   179     def __init__(self, predicate=None, many=False):
       
   180         BaseSerializer.__init__(self, predicate=predicate, many=many)
       
   181         self.opts = ModelSerializerOptions(self.Meta)        
       
   182