示例#1
0
 def start_serialization(self):
     """
     Start serialization -- open the XML document and the root element.
     """
     if (self.root):
         self.xml = XmlPrinter(
             self.stream,
             self.options.get("encoding", settings.DEFAULT_CHARSET))
         self.xml.startDocument()
         self.xml.startElement("django-objects", {"version": "1.0"})
示例#2
0
def xslt_param_builder(arg):
    """
    Returns the supplied arg ready for parameter injection to the XSLT processor
    """
    stream = StringIO.StringIO()
    xml = XmlPrinter(stream, settings.DEFAULT_CHARSET)
    xml.characters(arg)

    byte_string = stream.getvalue()
    return prepare_string_param(byte_string.decode('utf-8'))
示例#3
0
 def start_serialization(self):
     """
     Start serialization -- open the XML document and the root element.
     """
     if (self.root):
         self.xml = XmlPrinter(self.stream, self.options.get("encoding", settings.DEFAULT_CHARSET))
         self.xml.startDocument()
         self.xml.startElement("django-objects", {"version" : "1.0"})
示例#4
0
class RecursiveXmlSerializer(xml_serializer.Serializer):
    """
    Serializes a queryset including related fields
    """
    def serialize(self, queryset, **options):
        """
        Serialize a queryset.
        THE OUTPUT OF THIS SERIALIZER IS NOT MEANT TO BE SERIALIZED BACK
        INTO THE DB.        
        """
        self.options = options

        self.stream = options.get("stream", StringIO())
        self.selected_fields = options.get("fields")
        self.use_natural_keys = options.get("use_natural_keys", True)
        
        self.xml = options.get("xml", None)
        self.root = (self.xml == None)
        
        self.start_serialization()
        for obj in queryset:
            # hook for having custom serialization
            if hasattr(obj, '__serialize__'):
                obj.__serialize__(self.xml)
            else:
                self.serialize_object(obj)
        self.end_serialization()
        return self.getvalue()
    
    def serialize_object(self, obj):
        """
        Write one item to the object stream
        """
        self.start_object(obj)
        for field in obj._meta.local_fields:
            if field.serialize and getattr(field, 'include_in_xml', True):
                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)

        # recursively serialize all foreign key relations
        for (foreign_key_descriptor_name, foreign_key_descriptor ) in get_foreign_key_desciptors(obj):
            # don't follow foreign keys that have a 'nofollow' attribute
            if foreign_key_descriptor.related.field.serialize \
                and not hasattr(foreign_key_descriptor.related.field, 'nofollow'):
                bound_foreign_key_descriptor = foreign_key_descriptor.__get__(obj)
                s = RecursiveXmlSerializer()                
                s.serialize( bound_foreign_key_descriptor.all(), xml=self.xml, stream=self.stream)

        #recursively serialize all one to one relations
        # TODO: make this work for non abstract inheritance but without infinite recursion
        # for (one_to_one_descriptor_name, one_to_one_descriptor) in get_one_to_one_descriptors(obj):
        #     related_objects = []
        #     try:
        #         related_object = one_to_one_descriptor.__get__(obj)
        #         related_objects.append(related_object)
        #     except Exception as e:
        #         pass
        # 
        #     s = RecursiveXmlSerializer()                
        #     s.serialize( related_objects, xml=self.xml, stream=self.stream)

        # add generic relations
        for (generic_relation_descriptor_name, generic_relation_descriptor) in get_generic_relation_descriptors(obj):
            # generic relations always have serialize set to False so we always include them.
            bound_generic_relation_descriptor = generic_relation_descriptor.__get__(obj)
            s = RecursiveXmlSerializer()                
            s.serialize( bound_generic_relation_descriptor.all(), xml=self.xml, stream=self.stream)
        
        #serialize the default field descriptors:
        for (default_field_descriptor_name, default_field_descriptor) in get_default_field_descriptors(obj):
            if default_field_descriptor.serialize:
                self.handle_field(obj, default_field_descriptor)
        
        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)
        
    def start_serialization(self):
        """
        Start serialization -- open the XML document and the root element.
        """
        if (self.root):
            self.xml = XmlPrinter(self.stream, self.options.get("encoding", settings.DEFAULT_CHARSET))
            self.xml.startDocument()
            self.xml.startElement("django-objects", {"version" : "1.0"})


    def end_serialization(self):
        """
        End serialization -- end the document.
        """
        if (self.root):
            self.indent(0)
            self.xml.endElement("django-objects")
            self.xml.endDocument()


    def handle_field(self, obj, field):
        """
        Called to handle each field on an object (except for ForeignKeys and
        ManyToManyFields)
        """
        self.indent(2)

        field_attrs = {
            "name" : field.name,
            "type" : field.get_internal_type()
        }
        # handle fields with a extra_attrs set as speciul
        if hasattr(field, 'extra_attrs'):
            if field.extra_attrs:
                for (key, value) in field.extra_attrs.iteritems():
                    field_attrs[key] = force_unicode(value)

            field_attrs['name'] = field.name.replace('_', '.')

        self.xml.startElement("field", field_attrs)

        # Checks for a custom value serializer 
        if not hasattr(field, '__serialize__'):
            # Get a "string version" of the object's data.
            if getattr(obj, field.name) is not None:
                self.xml.characters(field.value_to_string(obj))
            else:
                self.xml.addQuickElement("None")
        else:
            field.__serialize__(obj, self.xml)

        self.xml.endElement("field")

    def handle_fk_field(self, obj, field):
        """
        Called to handle a ForeignKey (we need to treat them slightly
        differently from regular fields).
        """
        self._start_relational_field(field)
        related = getattr(obj, field.name)
        if related is not None:
            if self.use_natural_keys and hasattr(related, 'natural_key'):
                # If related object has a natural key, use it
                related = related.natural_key()
                # Iterable natural keys are rolled out as subelements
                for key_value in related:
                    self.xml.startElement("natural", {})
                    self.xml.characters(smart_unicode(key_value))
                    self.xml.endElement("natural")
            else:
                if field.rel.field_name == related._meta.pk.name:
                    # Related to remote object via primary key
                    related = related._get_pk_val()
                else:
                    # Related to remote object via other field
                    related = getattr(related, field.rel.field_name)
                self.xml.characters(smart_unicode(related))
        else:
            self.xml.addQuickElement("None")
        self.xml.endElement("field")

    def handle_m2m_field(self, obj, field):
        """
        while easymode follows inverse relations for foreign keys,
        for manytomayfields it follows the forward relation.
        
        While easymode excludes all relations to "self" you could
        still create a loop if you add one extra level of indirection.
        """
        
        if field.rel.through._meta.auto_created:#  and obj.__class__ is not field.rel.to:
            # keep approximate recursion level
            with recursion_depth('handle_m2m_field') as recursion_level:
                
                # a stack trace is better than python crashing.
                if recursion_level > getattr(settings, 'RECURSION_LIMIT', sys.getrecursionlimit() / 10):
                    raise Exception(MANY_TO_MANY_RECURSION_LIMIT_ERROR % 
                            (field.name, obj.__class__.__name__, field.rel.to.__name__))

                self._start_relational_field(field)

                s = RecursiveXmlSerializer()
                s.serialize( getattr(obj, field.name).iterator(), xml=self.xml, stream=self.stream)

                self.xml.endElement("field")
示例#5
0
def startDocumentOnlyOnce(self):
    if hasattr(self, 'allready_called'):
        return
    self.allready_called = True
    XmlPrinter.startDocument(self)
示例#6
0
class RecursiveXmlSerializer(xml_serializer.Serializer):
    """
    Serializes a queryset including related fields
    """
    def serialize(self, queryset, **options):
        """
        Serialize a queryset.
        THE OUTPUT OF THIS SERIALIZER IS NOT MEANT TO BE SERIALIZED BACK
        INTO THE DB.        
        """
        self.options = options

        self.stream = options.get("stream", StringIO())
        self.selected_fields = options.get("fields")
        self.use_natural_keys = options.get("use_natural_keys", True)

        self.xml = options.get("xml", None)
        self.root = (self.xml == None)

        self.start_serialization()
        for obj in queryset:
            self.start_object(obj)
            for field in obj._meta.local_fields:
                if field.serialize and getattr(field, 'include_in_xml', True):
                    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)

            # recursively serialize all foreign key relations
            for (foreign_key_descriptor_name,
                 foreign_key_descriptor) in get_foreign_key_desciptors(obj):
                # don't follow foreign keys that have a 'nofollow' attribute
                if foreign_key_descriptor.related.field.serialize \
                    and not hasattr(foreign_key_descriptor.related.field, 'nofollow'):
                    bound_foreign_key_descriptor = foreign_key_descriptor.__get__(
                        obj)
                    s = RecursiveXmlSerializer()
                    s.serialize(bound_foreign_key_descriptor.all(),
                                xml=self.xml,
                                stream=self.stream)

            #recursively serialize all one to one relations
            # TODO: make this work for non abstract inheritance but without infinite recursion
            # for (one_to_one_descriptor_name, one_to_one_descriptor) in get_one_to_one_descriptors(obj):
            #     related_objects = []
            #     try:
            #         related_object = one_to_one_descriptor.__get__(obj)
            #         related_objects.append(related_object)
            #     except Exception as e:
            #         pass
            #
            #     s = RecursiveXmlSerializer()
            #     s.serialize( related_objects, xml=self.xml, stream=self.stream)

            # add generic relations
            for (generic_relation_descriptor_name, generic_relation_descriptor
                 ) in get_generic_relation_descriptors(obj):
                # generic relations always have serialize set to False so we always include them.
                bound_generic_relation_descriptor = generic_relation_descriptor.__get__(
                    obj)
                s = RecursiveXmlSerializer()
                s.serialize(bound_generic_relation_descriptor.all(),
                            xml=self.xml,
                            stream=self.stream)

            #serialize the default field descriptors:
            for (default_field_descriptor_name, default_field_descriptor
                 ) in get_default_field_descriptors(obj):
                if default_field_descriptor.serialize:
                    self.handle_field(obj, default_field_descriptor)

            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 start_serialization(self):
        """
        Start serialization -- open the XML document and the root element.
        """
        if (self.root):
            self.xml = XmlPrinter(
                self.stream,
                self.options.get("encoding", settings.DEFAULT_CHARSET))
            self.xml.startDocument()
            self.xml.startElement("django-objects", {"version": "1.0"})

    def end_serialization(self):
        """
        End serialization -- end the document.
        """
        if (self.root):
            self.indent(0)
            self.xml.endElement("django-objects")
            self.xml.endDocument()

    def handle_field(self, obj, field):
        """
        Called to handle each field on an object (except for ForeignKeys and
        ManyToManyFields)
        """
        self.indent(2)

        field_attrs = {"name": field.name, "type": field.get_internal_type()}
        # handle fields with a extra_attrs set as speciul
        if hasattr(field, 'extra_attrs'):
            if field.extra_attrs:
                for (key, value) in field.extra_attrs.iteritems():
                    field_attrs[key] = force_unicode(value)

            field_attrs['name'] = field.name.replace('_', '.')

        self.xml.startElement("field", field_attrs)

        # Checks for a custom value serializer
        if not hasattr(field, 'custom_value_serializer'):
            # Get a "string version" of the object's data.
            if getattr(obj, field.name) is not None:
                self.xml.characters(field.value_to_string(obj))
            else:
                self.xml.addQuickElement("None")
        else:
            field.custom_value_serializer(obj, self.xml)

        self.xml.endElement("field")

    def handle_fk_field(self, obj, field):
        """
        Called to handle a ForeignKey (we need to treat them slightly
        differently from regular fields).
        """
        self._start_relational_field(field)
        related = getattr(obj, field.name)
        if related is not None:
            if self.use_natural_keys and hasattr(related, 'natural_key'):
                # If related object has a natural key, use it
                related = related.natural_key()
                # Iterable natural keys are rolled out as subelements
                for key_value in related:
                    self.xml.startElement("natural", {})
                    self.xml.characters(smart_unicode(key_value))
                    self.xml.endElement("natural")
            else:
                if field.rel.field_name == related._meta.pk.name:
                    # Related to remote object via primary key
                    related = related._get_pk_val()
                else:
                    # Related to remote object via other field
                    related = getattr(related, field.rel.field_name)
                self.xml.characters(smart_unicode(related))
        else:
            self.xml.addQuickElement("None")
        self.xml.endElement("field")

    def handle_m2m_field(self, obj, field):
        """
        while easymode follows inverse relations for foreign keys,
        for manytomayfields it follows the forward relation.
        
        While easymode excludes all relations to "self" you could
        still create a loop if you add one extra level of indirection.
        """

        if field.rel.through._meta.auto_created:  #  and obj.__class__ is not field.rel.to:
            # keep approximate recursion level
            with recursion_depth('handle_m2m_field') as recursion_level:

                # a stack trace is better than python crashing.
                if recursion_level > getattr(settings, 'RECURSION_LIMIT',
                                             sys.getrecursionlimit() / 10):
                    raise Exception(MANY_TO_MANY_RECURSION_LIMIT_ERROR %
                                    (field.name, obj.__class__.__name__,
                                     field.rel.to.__name__))

                self._start_relational_field(field)

                s = RecursiveXmlSerializer()
                s.serialize(getattr(obj, field.name).iterator(),
                            xml=self.xml,
                            stream=self.stream)

                self.xml.endElement("field")
示例#7
0
def startDocumentOnlyOnce(self):
    if hasattr(self, 'allready_called'):
        return
    self.allready_called = True
    XmlPrinter.startDocument(self)