@@ -292,7 +292,7 @@ def _handle_object(self, node):
292292
293293 field_names = {f .name for f in Model ._meta .get_fields ()}
294294 # Deserialize each field.
295- for field_node in node . getElementsByTagName ( "field" ):
295+ for field_node in getChildrenByTagName ( node , "field" ):
296296 # If the field is missing the name attribute, bail (are you
297297 # sensing a pattern here?)
298298 field_name = field_node .getAttribute ("name" )
@@ -319,12 +319,12 @@ def _handle_object(self, node):
319319 [
320320 (
321321 None
322- if nat_node . getElementsByTagName ( "None" )
322+ if getChildrenByTagName ( nat_node , "None" )
323323 else getInnerText (nat_node ).strip ()
324324 )
325- for nat_node in obj_node . getElementsByTagName ( "natural" )
325+ for nat_node in getChildrenByTagName ( obj_node , "natural" )
326326 ]
327- for obj_node in field_node . getElementsByTagName ( "object" )
327+ for obj_node in getChildrenByTagName ( field_node , "object" )
328328 ]
329329 else :
330330 m2m_data [field .name ] = value
@@ -336,15 +336,15 @@ def _handle_object(self, node):
336336 deferred_fields [field ] = [
337337 (
338338 None
339- if k . getElementsByTagName ( "None" )
339+ if getChildrenByTagName ( k , "None" )
340340 else getInnerText (k ).strip ()
341341 )
342- for k in field_node . getElementsByTagName ( "natural" )
342+ for k in getChildrenByTagName ( field_node , "natural" )
343343 ]
344344 else :
345345 data [field .attname ] = value
346346 else :
347- if field_node . getElementsByTagName ( "None" ):
347+ if getChildrenByTagName ( field_node , "None" ):
348348 value = None
349349 else :
350350 value = field .to_python (getInnerText (field_node ).strip ())
@@ -363,8 +363,8 @@ def _handle_fk_field_node(self, node, field):
363363 Handle a <field> node for a ForeignKey
364364 """
365365 # Check if there is a child node named 'None', returning None if so.
366- natural_keys = node . getElementsByTagName ( "natural" )
367- if node . getElementsByTagName ( "None" ) and not natural_keys :
366+ natural_keys = getChildrenByTagName ( node , "natural" )
367+ if getChildrenByTagName ( node , "None" ) and not natural_keys :
368368 return None
369369 else :
370370 model = field .remote_field .model
@@ -374,7 +374,7 @@ def _handle_fk_field_node(self, node, field):
374374 # key
375375 field_value = []
376376 for k in natural_keys :
377- if k . getElementsByTagName ( "None" ):
377+ if getChildrenByTagName ( k , "None" ):
378378 field_value .append (None )
379379 else :
380380 field_value .append (getInnerText (k ).strip ())
@@ -414,13 +414,13 @@ def _handle_m2m_field_node(self, node, field):
414414 if hasattr (default_manager , "get_by_natural_key" ):
415415
416416 def m2m_convert (n ):
417- keys = n . getElementsByTagName ( "natural" )
417+ keys = getChildrenByTagName ( n , "natural" )
418418 if keys :
419419 # If there are 'natural' subelements, it must be a natural
420420 # key
421421 field_value = []
422422 for k in keys :
423- if k . getElementsByTagName ( "None" ):
423+ if getChildrenByTagName ( k , "None" ):
424424 field_value .append (None )
425425 else :
426426 field_value .append (getInnerText (k ).strip ())
@@ -441,7 +441,7 @@ def m2m_convert(n):
441441
442442 values = []
443443 try :
444- for c in node . getElementsByTagName ( "object" ):
444+ for c in getChildrenByTagName ( node , "object" ):
445445 values .append (m2m_convert (c ))
446446 except SuspiciousOperation :
447447 raise
@@ -479,6 +479,25 @@ def check_element_type(element):
479479 return element .nodeType in (element .TEXT_NODE , element .CDATA_SECTION_NODE )
480480
481481
482+ def getChildrenByTagName (node , tag_name ):
483+ """
484+ Like Element.getElementsByTagName() but return only direct children.
485+
486+ Element.getElementsByTagName() searches all descendants (direct children,
487+ children's children, etc.). This prevents correct deserialization of
488+ third-party nested fields. For example:
489+
490+ <field name="author" type="EmbeddedModelField">
491+ <object model="app.Model">
492+ <field name="id" type="..."><None></None></field>
493+ """
494+ return [
495+ n
496+ for n in node .childNodes
497+ if n .nodeType == node .ELEMENT_NODE and n .tagName == tag_name
498+ ]
499+
500+
482501def getInnerText (node ):
483502 return "" .join (
484503 [child .data for child in node .childNodes if check_element_type (child )]
0 commit comments