@@ -500,66 +500,63 @@ def _clear_changed_fields(self):
500500
501501 self ._changed_fields = []
502502
503- def _nestable_types_changed_fields (self , changed_fields , key , data , inspected ):
503+ def _nestable_types_changed_fields (self , changed_fields , base_key , data ):
504+ """Inspect nested data for changed fields
505+
506+ :param changed_fields: Previously collected changed fields
507+ :param base_key: The base key that must be used to prepend changes to this data
508+ :param data: data to inspect for changes
509+ """
504510 # Loop list / dict fields as they contain documents
505511 # Determine the iterator to use
506512 if not hasattr (data , 'items' ):
507513 iterator = enumerate (data )
508514 else :
509515 iterator = data .iteritems ()
510516
511- for index , value in iterator :
512- list_key = '%s%s.' % (key , index )
517+ for index_or_key , value in iterator :
518+ item_key = '%s%s.' % (base_key , index_or_key )
513519 # don't check anything lower if this key is already marked
514520 # as changed.
515- if list_key [:- 1 ] in changed_fields :
521+ if item_key [:- 1 ] in changed_fields :
516522 continue
523+
517524 if hasattr (value , '_get_changed_fields' ):
518- changed = value ._get_changed_fields (inspected )
519- changed_fields += ['%s%s' % (list_key , k )
520- for k in changed if k ]
525+ changed = value ._get_changed_fields ()
526+ changed_fields += ['%s%s' % (item_key , k ) for k in changed if k ]
521527 elif isinstance (value , (list , tuple , dict )):
522528 self ._nestable_types_changed_fields (
523- changed_fields , list_key , value , inspected )
529+ changed_fields , item_key , value )
524530
525- def _get_changed_fields (self , inspected = None ):
531+ def _get_changed_fields (self ):
526532 """Return a list of all fields that have explicitly been changed.
527533 """
528534 EmbeddedDocument = _import_class ('EmbeddedDocument' )
529- DynamicEmbeddedDocument = _import_class ('DynamicEmbeddedDocument' )
530535 ReferenceField = _import_class ('ReferenceField' )
531536 GenericReferenceField = _import_class ('GenericReferenceField' )
532537 SortedListField = _import_class ('SortedListField' )
533538
534539 changed_fields = []
535540 changed_fields += getattr (self , '_changed_fields' , [])
536541
537- inspected = inspected or set ()
538- if hasattr (self , 'id' ) and isinstance (self .id , Hashable ):
539- if self .id in inspected :
540- return changed_fields
541- inspected .add (self .id )
542-
543542 for field_name in self ._fields_ordered :
544543 db_field_name = self ._db_field_map .get (field_name , field_name )
545544 key = '%s.' % db_field_name
546545 data = self ._data .get (field_name , None )
547546 field = self ._fields .get (field_name )
548547
549- if hasattr (data , 'id' ):
550- if data .id in inspected :
551- continue
552- if isinstance (field , ReferenceField ):
548+ if db_field_name in changed_fields :
549+ # Whole field already marked as changed, no need to go further
550+ continue
551+
552+ if isinstance (field , ReferenceField ): # Don't follow referenced documents
553553 continue
554- elif (
555- isinstance (data , (EmbeddedDocument , DynamicEmbeddedDocument )) and
556- db_field_name not in changed_fields
557- ):
554+
555+ if isinstance (data , EmbeddedDocument ):
558556 # Find all embedded fields that have been changed
559- changed = data ._get_changed_fields (inspected )
557+ changed = data ._get_changed_fields ()
560558 changed_fields += ['%s%s' % (key , k ) for k in changed if k ]
561- elif (isinstance (data , (list , tuple , dict )) and
562- db_field_name not in changed_fields ):
559+ elif isinstance (data , (list , tuple , dict )):
563560 if (hasattr (field , 'field' ) and
564561 isinstance (field .field , (ReferenceField , GenericReferenceField ))):
565562 continue
@@ -570,7 +567,7 @@ def _get_changed_fields(self, inspected=None):
570567 continue
571568
572569 self ._nestable_types_changed_fields (
573- changed_fields , key , data , inspected )
570+ changed_fields , key , data )
574571 return changed_fields
575572
576573 def _delta (self ):
0 commit comments