mirror of
https://github.com/django/django.git
synced 2024-11-30 23:20:50 +01:00
Fixed #28324 -- Made feedgenerators write feeds with deterministically ordered attributes.
This commit is contained in:
parent
335a8d7895
commit
d0f59054d0
@ -2,7 +2,6 @@
|
||||
XML serializer.
|
||||
"""
|
||||
|
||||
from collections import OrderedDict
|
||||
from xml.dom import pulldom
|
||||
from xml.sax import handler
|
||||
from xml.sax.expatreader import ExpatParser as _ExpatParser
|
||||
@ -47,7 +46,7 @@ class Serializer(base.Serializer):
|
||||
raise base.SerializationError("Non-model object (%s) encountered during serialization" % type(obj))
|
||||
|
||||
self.indent(1)
|
||||
attrs = OrderedDict([("model", str(obj._meta))])
|
||||
attrs = {'model': str(obj._meta)}
|
||||
if not self.use_natural_primary_keys or not hasattr(obj, 'natural_key'):
|
||||
obj_pk = obj.pk
|
||||
if obj_pk is not None:
|
||||
@ -68,10 +67,10 @@ class Serializer(base.Serializer):
|
||||
ManyToManyFields).
|
||||
"""
|
||||
self.indent(2)
|
||||
self.xml.startElement("field", OrderedDict([
|
||||
("name", field.name),
|
||||
("type", field.get_internal_type()),
|
||||
]))
|
||||
self.xml.startElement('field', {
|
||||
'name': field.name,
|
||||
'type': field.get_internal_type(),
|
||||
})
|
||||
|
||||
# Get a "string version" of the object's data.
|
||||
if getattr(obj, field.name) is not None:
|
||||
@ -140,11 +139,11 @@ class Serializer(base.Serializer):
|
||||
def _start_relational_field(self, field):
|
||||
"""Output the <field> element for relational fields."""
|
||||
self.indent(2)
|
||||
self.xml.startElement("field", OrderedDict([
|
||||
("name", field.name),
|
||||
("rel", field.remote_field.__class__.__name__),
|
||||
("to", str(field.remote_field.model._meta)),
|
||||
]))
|
||||
self.xml.startElement('field', {
|
||||
'name': field.name,
|
||||
'rel': field.remote_field.__class__.__name__,
|
||||
'to': str(field.remote_field.model._meta),
|
||||
})
|
||||
|
||||
|
||||
class Deserializer(base.Deserializer):
|
||||
|
@ -3,6 +3,7 @@ Utilities for XML generation/parsing.
|
||||
"""
|
||||
|
||||
import re
|
||||
from collections import OrderedDict
|
||||
from xml.sax.saxutils import XMLGenerator
|
||||
|
||||
|
||||
@ -26,3 +27,8 @@ class SimplerXMLGenerator(XMLGenerator):
|
||||
# See http://www.w3.org/International/questions/qa-controls
|
||||
raise UnserializableContentError("Control characters are not supported in XML 1.0")
|
||||
XMLGenerator.characters(self, content)
|
||||
|
||||
def startElement(self, name, attrs):
|
||||
# Sort attrs for a deterministic output.
|
||||
sorted_attrs = OrderedDict(sorted(attrs.items())) if attrs else attrs
|
||||
super().startElement(name, sorted_attrs)
|
||||
|
@ -126,6 +126,11 @@ class FeedgeneratorTest(unittest.TestCase):
|
||||
feed.add_item('item_title', 'item_link', 'item_description')
|
||||
feed.writeString('utf-8')
|
||||
|
||||
def test_deterministic_attribute_order(self):
|
||||
feed = feedgenerator.Atom1Feed('title', '/link/', 'desc')
|
||||
feed_content = feed.writeString('utf-8')
|
||||
self.assertIn('href="/link/" rel="alternate"', feed_content)
|
||||
|
||||
|
||||
class FeedgeneratorDBTest(TestCase):
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user