Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(80)

Side by Side Diff: appengine_django/serializer/xml.py

Issue 950: Google App Engine Django - Deserialize db.DateTimeProperty SVN Base: http://google-app-engine-django.googlecode.com/svn/trunk/
Patch Set: Created 3 months, 2 weeks ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
OLDNEW
1 #!/usr/bin/python2.4 1 #!/usr/bin/python2.4
2 # 2 #
3 # Copyright 2008 Google Inc. 3 # Copyright 2008 Google Inc.
4 # 4 #
5 # Licensed under the Apache License, Version 2.0 (the "License"); 5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License. 6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at 7 # You may obtain a copy of the License at
8 # 8 #
9 # http://www.apache.org/licenses/LICENSE-2.0 9 # http://www.apache.org/licenses/LICENSE-2.0
10 # 10 #
11 # Unless required by applicable law or agreed to in writing, software 11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS, 12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and 14 # See the License for the specific language governing permissions and
15 # limitations under the License. 15 # limitations under the License.
16 16
17 17
18 """ 18 """
19 Replaces the default Django XML serializer with one that uses the built in 19 Replaces the default Django XML serializer with one that uses the built in
20 ToXml method for each entity. 20 ToXml method for each entity.
21 """ 21 """
22 22
23 import datetime
24 import time
23 import re 25 import re
24 26
25 from django.conf import settings 27 from django.conf import settings
26 from django.core.serializers import base 28 from django.core.serializers import base
27 from django.core.serializers import xml_serializer 29 from django.core.serializers import xml_serializer
28 from django.db import models 30 from django.db import models
29 31
30 from google.appengine.api import datastore_types 32 from google.appengine.api import datastore_types
31 from google.appengine.ext import db 33 from google.appengine.ext import db
32 34
33 from python import FakeParent 35 from appengine_django.serializer.python import FakeParent
36 from appengine_django.serializer.python import DATE_FORMAT
37 from appengine_django.serializer.python import TIME_FORMAT
34 38
35 getInnerText = xml_serializer.getInnerText 39 getInnerText = xml_serializer.getInnerText
36 40
37 41
38 class Serializer(xml_serializer.Serializer): 42 class Serializer(xml_serializer.Serializer):
39 """A Django Serializer class to convert datastore models to XML. 43 """A Django Serializer class to convert datastore models to XML.
40 44
41 This class relies on the ToXml method of the entity behind each model to do 45 This class relies on the ToXml method of the entity behind each model to do
42 the hard work. 46 the hard work.
43 """ 47 """
44 48
45 def __init__(self, *args, **kwargs): 49 def __init__(self, *args, **kwargs):
46 super(Serializer, self).__init__(*args, **kwargs) 50 super(Serializer, self).__init__(*args, **kwargs)
47 self._objects = [] 51 self._objects = []
48 52
49 def handle_field(self, obj, field): 53 def handle_field(self, obj, field):
50 """Fields are not handled individually.""" 54 """Fields are not handled individually."""
51 pass 55 pass
52 56
53 def handle_fk_field(self, obj, field): 57 def handle_fk_field(self, obj, field):
54 """Fields are not handled individually.""" 58 """Fields are not handled individually."""
55 pass 59 pass
56 60
57 def start_object(self, obj): 61 def start_object(self, obj):
58 """Nothing needs to be done to start an object.""" 62 """Nothing needs to be done to start an object."""
59 pass 63 pass
60 64
61 def end_object(self, obj): 65 def end_object(self, obj):
62 """Serialize the object to XML and add to the list of objects to output. 66 """Serialize the object to XML and add to the list of objects to output.
63 67
64 The output of ToXml is manipulated to replace the datastore model name in 68 The output of ToXml is manipulated to replace the datastore model name in
65 the "kind" tag with the Django model name (which includes the Django 69 the "kind" tag with the Django model name (which includes the Django
66 application name) to make importing easier. 70 application name) to make importing easier.
67 """ 71 """
68 xml = obj._entity.ToXml() 72 xml = obj._entity.ToXml()
69 xml = xml.replace(u"""kind="%s" """ % obj._entity.kind(), 73 xml = xml.replace(u"""kind="%s" """ % obj._entity.kind(),
70 u"""kind="%s" """ % unicode(obj._meta)) 74 u"""kind="%s" """ % unicode(obj._meta))
71 self._objects.append(xml) 75 self._objects.append(xml)
72 76
73 def getvalue(self): 77 def getvalue(self):
74 """Wrap the serialized objects with XML headers and return.""" 78 """Wrap the serialized objects with XML headers and return."""
75 str = u"""<?xml version="1.0" encoding="utf-8"?>\n""" 79 str = u"""<?xml version="1.0" encoding="utf-8"?>\n"""
76 str += u"""<django-objects version="1.0">\n""" 80 str += u"""<django-objects version="1.0">\n"""
77 str += u"".join(self._objects) 81 str += u"".join(self._objects)
78 str += u"""</django-objects>""" 82 str += u"""</django-objects>"""
79 return str 83 return str
80 84
81 85
82 class Deserializer(xml_serializer.Deserializer): 86 class Deserializer(xml_serializer.Deserializer):
83 """A Django Deserializer class to convert XML to Django objects. 87 """A Django Deserializer class to convert XML to Django objects.
84 88
85 This is a fairly manualy and simplistic XML parser, it supports just enough 89 This is a fairly manualy and simplistic XML parser, it supports just enough
86 functionality to read the keys and fields for an entity from the XML file and 90 functionality to read the keys and fields for an entity from the XML file and
87 construct a model object. 91 construct a model object.
88 """ 92 """
89 93
90 def next(self): 94 def next(self):
91 """Replacement next method to look for 'entity'. 95 """Replacement next method to look for 'entity'.
92 96
93 The default next implementation exepects 'object' nodes which is not 97 The default next implementation exepects 'object' nodes which is not
94 what the entity's ToXml output provides. 98 what the entity's ToXml output provides.
95 """ 99 """
96 for event, node in self.event_stream: 100 for event, node in self.event_stream:
97 if event == "START_ELEMENT" and node.nodeName == "entity": 101 if event == "START_ELEMENT" and node.nodeName == "entity":
98 self.event_stream.expandNode(node) 102 self.event_stream.expandNode(node)
99 return self._handle_object(node) 103 return self._handle_object(node)
100 raise StopIteration 104 raise StopIteration
101 105
102 def _handle_object(self, node): 106 def _handle_object(self, node):
103 """Convert an <entity> node to a DeserializedObject""" 107 """Convert an <entity> node to a DeserializedObject"""
104 Model = self._get_model_from_node(node, "kind") 108 Model = self._get_model_from_node(node, "kind")
105 data = {} 109 data = {}
106 key = db.Key(node.getAttribute("key")) 110 key = db.Key(node.getAttribute("key"))
107 if key.name(): 111 if key.name():
108 data["key_name"] = key.name() 112 data["key_name"] = key.name()
109 parent = None 113 parent = None
110 if key.parent(): 114 if key.parent():
111 parent = FakeParent(key.parent()) 115 parent = FakeParent(key.parent())
112 m2m_data = {} 116 m2m_data = {}
113 117
114 # Deseralize each field. 118 # Deseralize each field.
115 for field_node in node.getElementsByTagName("property"): 119 for field_node in node.getElementsByTagName("property"):
116 # If the field is missing the name attribute, bail (are you 120 # If the field is missing the name attribute, bail (are you
117 # sensing a pattern here?) 121 # sensing a pattern here?)
118 field_name = field_node.getAttribute("name") 122 field_name = field_node.getAttribute("name")
119 if not field_name: 123 if not field_name:
120 raise base.DeserializationError("<field> node is missing the 'name' " 124 raise base.DeserializationError("<field> node is missing the 'name' "
121 "attribute") 125 "attribute")
122 field = Model.properties()[field_name] 126 field = Model.properties()[field_name]
123 field_value = getInnerText(field_node).strip() 127 field_value = getInnerText(field_node).strip()
124 128
125 if isinstance(field, db.Reference): 129 if isinstance(field, db.Reference):
GvR 2008/05/15 18:32:28 PS. Should use db.ReferenceProperty here -- db.Ref
126 m = re.match("tag:.*\[(.*)\]", field_value) 130 m = re.match("tag:.*\[(.*)\]", field_value)
127 if not m: 131 if not m:
128 raise base.DeserializationError(u"Invalid reference value: '%s'" % 132 raise base.DeserializationError(u"Invalid reference value: '%s'" %
129 field_value) 133 field_value)
130 key = m.group(1) 134 key = m.group(1)
131 key_obj = db.Key(key) 135 key_obj = db.Key(key)
132 if not key_obj.name(): 136 if not key_obj.name():
133 raise base.DeserializationError(u"Cannot load Reference with " 137 raise base.DeserializationError(u"Cannot load Reference with "
134 "unnamed key: '%s'" % field_value) 138 "unnamed key: '%s'" % field_value)
135 data[field.name] = key_obj 139 data[field.name] = key_obj
136 else: 140 continue
137 data[field.name] = field.validate(field_value) 141
142 if isinstance(field, db.DateTimeProperty):
GvR 2008/05/13 16:40:54 Why the duplicated code? I guess this is another
143 try:
144 t = time.strptime(field_value.split(".")[0],
145 "%s %s"% (DATE_FORMAT, TIME_FORMAT))
146 d = datetime.datetime(*(t)[0:6])
147 field_value = d
148 except (ValueError, TypeError), e:
149 # Pass it on anyway, and hope the model can deal with it.
150 pass
151
152 data[field.name] = field.validate(field_value)
138 153
139 # Create the new model instance with all it's data, but no parent. 154 # Create the new model instance with all it's data, but no parent.
140 object = Model(**data) 155 object = Model(**data)
141 # Now add the parent into the hidden attribute, bypassing the type checks 156 # Now add the parent into the hidden attribute, bypassing the type checks
142 # in the Model's __init__ routine. 157 # in the Model's __init__ routine.
143 object._parent = parent 158 object._parent = parent
144 # When the deserialized object is saved our replacement DeserializedObject 159 # When the deserialized object is saved our replacement DeserializedObject
145 # class will set object._parent to force the real parent model to be loaded 160 # class will set object._parent to force the real parent model to be loaded
146 # the first time it is referenced. 161 # the first time it is referenced.
147 return base.DeserializedObject(object, m2m_data) 162 return base.DeserializedObject(object, m2m_data)
OLDNEW

Powered by Google App Engine
This is Rietveld r292