@@ -503,65 +503,62 @@ def _clear_changed_fields(self):
503503
504504 self ._changed_fields = []
505505
506- def _nestable_types_changed_fields (self , changed_fields , key , data , inspected ):
506+ def _nestable_types_changed_fields (self , changed_fields , base_key , data ):
507+ """Inspect nested data for changed fields
508+
509+ :param changed_fields: Previously collected changed fields
510+ :param base_key: The base key that must be used to prepend changes to this data
511+ :param data: data to inspect for changes
512+ """
507513 # Loop list / dict fields as they contain documents
508514 # Determine the iterator to use
509515 if not hasattr (data , 'items' ):
510516 iterator = enumerate (data )
511517 else :
512518 iterator = data .iteritems ()
513519
514- for index , value in iterator :
515- list_key = '%s%s.' % (key , index )
520+ for index_or_key , value in iterator :
521+ item_key = '%s%s.' % (base_key , index_or_key )
516522 # don't check anything lower if this key is already marked
517523 # as changed.
518- if list_key [:- 1 ] in changed_fields :
524+ if item_key [:- 1 ] in changed_fields :
519525 continue
526+
520527 if hasattr (value , '_get_changed_fields' ):
521- changed = value ._get_changed_fields (inspected )
522- changed_fields += ['%s%s' % (list_key , k )
523- for k in changed if k ]
528+ changed = value ._get_changed_fields ()
529+ changed_fields += ['%s%s' % (item_key , k ) for k in changed if k ]
524530 elif isinstance (value , (list , tuple , dict )):
525531 self ._nestable_types_changed_fields (
526- changed_fields , list_key , value , inspected )
532+ changed_fields , item_key , value )
527533
528- def _get_changed_fields (self , inspected = None ):
534+ def _get_changed_fields (self ):
529535 """Return a list of all fields that have explicitly been changed.
530536 """
531537 EmbeddedDocument = _import_class ('EmbeddedDocument' )
532- DynamicEmbeddedDocument = _import_class ('DynamicEmbeddedDocument' )
533538 ReferenceField = _import_class ('ReferenceField' )
534539 SortedListField = _import_class ('SortedListField' )
535540
536541 changed_fields = []
537542 changed_fields += getattr (self , '_changed_fields' , [])
538543
539- inspected = inspected or set ()
540- if hasattr (self , 'id' ) and isinstance (self .id , Hashable ):
541- if self .id in inspected :
542- return changed_fields
543- inspected .add (self .id )
544-
545544 for field_name in self ._fields_ordered :
546545 db_field_name = self ._db_field_map .get (field_name , field_name )
547546 key = '%s.' % db_field_name
548547 data = self ._data .get (field_name , None )
549548 field = self ._fields .get (field_name )
550549
551- if hasattr (data , 'id' ):
552- if data .id in inspected :
553- continue
554- if isinstance (field , ReferenceField ):
550+ if db_field_name in changed_fields :
551+ # Whole field already marked as changed, no need to go further
552+ continue
553+
554+ if isinstance (field , ReferenceField ): # Don't follow referenced documents
555555 continue
556- elif (
557- isinstance (data , (EmbeddedDocument , DynamicEmbeddedDocument )) and
558- db_field_name not in changed_fields
559- ):
556+
557+ if isinstance (data , EmbeddedDocument ):
560558 # Find all embedded fields that have been changed
561- changed = data ._get_changed_fields (inspected )
559+ changed = data ._get_changed_fields ()
562560 changed_fields += ['%s%s' % (key , k ) for k in changed if k ]
563- elif (isinstance (data , (list , tuple , dict )) and
564- db_field_name not in changed_fields ):
561+ elif isinstance (data , (list , tuple , dict )):
565562 if (hasattr (field , 'field' ) and
566563 isinstance (field .field , ReferenceField )):
567564 continue
@@ -572,7 +569,7 @@ def _get_changed_fields(self, inspected=None):
572569 continue
573570
574571 self ._nestable_types_changed_fields (
575- changed_fields , key , data , inspected )
572+ changed_fields , key , data )
576573 return changed_fields
577574
578575 def _delta (self ):
0 commit comments