|
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 |