How to change the root element and list-item eleme

2019-08-02 23:54发布

问题:

I am new to django-rest-framework i have working sample like

<root>
    <list-item>worrier1</list-item>
    <list-item>worrier2</list-item>
<root>

What i need is

<Hero>
    <worrier1>worrier1</worrier1>
    <worrier2>worrier2</worrier2>
<Hero>

回答1:

Those are hardcoded values, so the only chance you get, is to create custom renderer by overriding the XMLRenderer (which in effect would be pretty much the whole class) and use that custom renderer in your view.



回答2:

In the spirit of being helpful to anyone else who searches for this... Below is how you can subclass the XMLRenderer and override the root tag (previously "root") and item tags (previously "list-item") to whatever you like.

from django.utils.six.moves import StringIO
from django.utils.xmlutils import SimplerXMLGenerator
from rest_framework_xml.renderers import XMLRenderer

class ModifiedXMLRenderer(XMLRenderer):
    item_tag_name = "item"
    root_tag_name = "channel"

    def render(self, data, accepted_media_type=None, renderer_context=None):
        """
        Renders `data` into serialized XML.
        """
        if data is None:
            return ''

        stream = StringIO()

        xml = SimplerXMLGenerator(stream, self.charset)
        xml.startDocument()
        xml.startElement(self.root_tag_name, {})

        self._to_xml(xml, data)

        xml.endElement(self.root_tag_name)
        xml.endDocument()
        return stream.getvalue()

    def _to_xml(self, xml, data):
        if isinstance(data, (list, tuple)):
            for item in data:
                xml.startElement(self.item_tag_name, {})
                self._to_xml(xml, item)
                xml.endElement(self.item_tag_name)

        elif isinstance(data, dict):
            for key, value in six.iteritems(data):
                xml.startElement(key, {})
                self._to_xml(xml, value)
                xml.endElement(key)

        elif data is None:
            # Don't output any value
            pass

        else:
            xml.characters(smart_text(data))


回答3:

I don't think you need to go so far as to create a whole subclass, I was able to do it by overriding the instance variables after creating the instance and before running render, see below:

renderer = XMLRenderer()
renderer.item_tag_name = 'warrior'
renderer.root_tag_name = 'Hero'
content = renderer.render(serializer.data)

Hope that helps anyone else who stumbles by



回答4:

If you wish to do this generically you don't need to override too much of the class:

class MyXMLRenderer(XMLRenderer):
    """Override XML tag names."""

    root_tag_name = 'file'
    item_tag_name = 'instance'


回答5:

For anyone who wants to edit the actual package, you can go to your Python folder, site-packages, rest_framework_xml, and edit renderers.py

When you get there, you can edit: item_tag_name = 'list-item' and change this to item_tag_name = 'item'

Note: By doing this method, you are overriding the actual class. For my project, it does not matter, but if you intend to use the xml library for another Django project, just keep this in mind.