Adust the as_table tag to render a pick link if appropriate
The templates are adjusted to pass on a 'reference' value, which
is the url_name of the view from which the entity should be picked.
The as_table (and related) function(s) construct and then pass on
this argument and enable takes_contex so that we have access to the
context of the enclosing template.
We only extract ReferenceProperties that end with '_link_id' since
that is how all RP's are currently named. It is not possible to
create a field with the same name as the RP, as GAE will try to
interpret it's contents as the key of an entity before even calling
any function we can override.
Patch by: Sverre Rabbelier
"""Module for abstract serializer/unserializer base classes."""from StringIO import StringIOfrom django.db import modelsfrom django.utils.encoding import smart_str, smart_unicodefrom django.utils import datetime_safeclass SerializationError(Exception): """Something bad happened during serialization.""" passclass DeserializationError(Exception): """Something bad happened during deserialization.""" passclass Serializer(object): """ Abstract serializer base class. """ # Indicates if the implemented serializer is only available for # internal Django use. internal_use_only = False def serialize(self, queryset, **options): """ Serialize a queryset. """ self.options = options self.stream = options.get("stream", StringIO()) self.selected_fields = options.get("fields") self.start_serialization() for obj in queryset: self.start_object(obj) for field in obj._meta.local_fields: if field.serialize: if field.rel is None: if self.selected_fields is None or field.attname in self.selected_fields: self.handle_field(obj, field) else: if self.selected_fields is None or field.attname[:-3] in self.selected_fields: self.handle_fk_field(obj, field) for field in obj._meta.many_to_many: if field.serialize: if self.selected_fields is None or field.attname in self.selected_fields: self.handle_m2m_field(obj, field) self.end_object(obj) self.end_serialization() return self.getvalue() def get_string_value(self, obj, field): """ Convert a field's value to a string. """ return smart_unicode(field.value_to_string(obj)) def start_serialization(self): """ Called when serializing of the queryset starts. """ raise NotImplementedError def end_serialization(self): """ Called when serializing of the queryset ends. """ pass def start_object(self, obj): """ Called when serializing of an object starts. """ raise NotImplementedError def end_object(self, obj): """ Called when serializing of an object ends. """ pass def handle_field(self, obj, field): """ Called to handle each individual (non-relational) field on an object. """ raise NotImplementedError def handle_fk_field(self, obj, field): """ Called to handle a ForeignKey field. """ raise NotImplementedError def handle_m2m_field(self, obj, field): """ Called to handle a ManyToManyField. """ raise NotImplementedError def getvalue(self): """ Return the fully serialized queryset (or None if the output stream is not seekable). """ if callable(getattr(self.stream, 'getvalue', None)): return self.stream.getvalue()class Deserializer(object): """ Abstract base deserializer class. """ def __init__(self, stream_or_string, **options): """ Init this serializer given a stream or a string """ self.options = options if isinstance(stream_or_string, basestring): self.stream = StringIO(stream_or_string) else: self.stream = stream_or_string # hack to make sure that the models have all been loaded before # deserialization starts (otherwise subclass calls to get_model() # and friends might fail...) models.get_apps() def __iter__(self): return self def next(self): """Iteration iterface -- return the next item in the stream""" raise NotImplementedErrorclass DeserializedObject(object): """ A deserialized model. Basically a container for holding the pre-saved deserialized data along with the many-to-many data saved with the object. Call ``save()`` to save the object (with the many-to-many data) to the database; call ``save(save_m2m=False)`` to save just the object fields (and not touch the many-to-many stuff.) """ def __init__(self, obj, m2m_data=None): self.object = obj self.m2m_data = m2m_data def __repr__(self): return "<DeserializedObject: %s>" % smart_str(self.object) def save(self, save_m2m=True): # Call save on the Model baseclass directly. This bypasses any # model-defined save. The save is also forced to be raw. # This ensures that the data that is deserialized is literally # what came from the file, not post-processed by pre_save/save # methods. models.Model.save_base(self.object, raw=True) if self.m2m_data and save_m2m: for accessor_name, object_list in self.m2m_data.items(): setattr(self.object, accessor_name, object_list) # prevent a second (possibly accidental) call to save() from saving # the m2m data twice. self.m2m_data = None