def get_changes(self):
        """
        Returns the difference between the old and new sets of models as a 5-tuple:
        added_models, deleted_models, added_fields, deleted_fields, changed_fields
        """
        
        deleted_models = set()
        
        # See if anything's vanished
        for key in self.old_defs:
            if key not in self.new_defs:
                # We shouldn't delete it if it was managed=False
                old_fields, old_meta, old_m2ms = self.split_model_def(self.old_orm[key], self.old_defs[key])
                if old_meta.get("managed", "True") != "False":
                    # Alright, delete it.
                    yield ("DeleteModel", {
                        "model": self.old_orm[key], 
                        "model_def": old_fields,
                    })
                    # Also make sure we delete any M2Ms it had.
                    for fieldname in old_m2ms:
                        # Only delete its stuff if it wasn't a through=.
                        field = self.old_orm[key + ":" + fieldname]
                        if auto_through(field):
                            yield ("DeleteM2M", {"model": self.old_orm[key], "field": field})
                    # And any index/uniqueness constraints it had
                    for attr, operation in (("unique_together", "DeleteUnique"), ("index_together", "DeleteIndex")):
                        together = eval(old_meta.get(attr, "[]"))
                        if together:
                            # If it's only a single tuple, make it into the longer one
                            if isinstance(together[0], string_types):
                                together = [together]
                            # For each combination, make an action for it
                            for fields in together:
                                yield (operation, {
                                    "model": self.old_orm[key],
                                    "fields": [self.old_orm[key]._meta.get_field_by_name(x)[0] for x in fields],
                                })
                # We always add it in here so we ignore it later
                deleted_models.add(key)
        
        # Or appeared
        for key in self.new_defs:
            if key not in self.old_defs:
                # We shouldn't add it if it's managed=False
                new_fields, new_meta, new_m2ms = self.split_model_def(self.current_model_from_key(key), self.new_defs[key])
                if new_meta.get("managed", "True") != "False":
                    yield ("AddModel", {
                        "model": self.current_model_from_key(key), 
                        "model_def": new_fields,
                    })
                    # Also make sure we add any M2Ms it has.
                    for fieldname in new_m2ms:
                        # Only create its stuff if it wasn't a through=.
                        field = self.current_field_from_key(key, fieldname)
                        if auto_through(field):
                            yield ("AddM2M", {"model": self.current_model_from_key(key), "field": field})
                    # And any index/uniqueness constraints it has
                    for attr, operation in (("unique_together", "AddUnique"), ("index_together", "AddIndex")):
                        together = eval(new_meta.get(attr, "[]"))
                        if together:
                            # If it's only a single tuple, make it into the longer one
                            if isinstance(together[0], string_types):
                                together = [together]
                            # For each combination, make an action for it
                            for fields in together:
                                yield (operation, {
                                    "model": self.current_model_from_key(key),
                                    "fields": [self.current_model_from_key(key)._meta.get_field_by_name(x)[0] for x in fields],
                                })
        
        # Now, for every model that's stayed the same, check its fields.
        for key in self.old_defs:
            if key not in deleted_models:
                
                old_fields, old_meta, old_m2ms = self.split_model_def(self.old_orm[key], self.old_defs[key])
                new_fields, new_meta, new_m2ms = self.split_model_def(self.current_model_from_key(key), self.new_defs[key])
                
                # Do nothing for models which are now not managed.
                if new_meta.get("managed", "True") == "False":
                    continue
                
                # Find fields that have vanished.
                for fieldname in old_fields:
                    if fieldname not in new_fields:
                        # Don't do it for any fields we're ignoring
                        field = self.old_orm[key + ":" + fieldname]
                        field_allowed = True
                        for field_type in self.IGNORED_FIELD_TYPES:
                            if isinstance(field, field_type):
                                field_allowed = False
                        if field_allowed:
                            # Looks alright.
                            yield ("DeleteField", {
                                "model": self.old_orm[key],
                                "field": field,
                                "field_def": old_fields[fieldname],
                            })
                
                # And ones that have appeared
                for fieldname in new_fields:
                    if old_fields not in fieldname:
                        # Don't do it for any fields we're ignoring
                        field = self.current_field_from_key(key, fieldname)
                        field_allowed = True
                        for field_type in self.IGNORED_FIELD_TYPES:
                            if isinstance(field, field_type):
                                field_allowed = False
                        if field_allowed:
                            # Looks alright.
                            yield ("AddField", {
                                "model": self.current_model_from_key(key),
                                "field": field,
                                "field_def": new_fields[fieldname],
                            })
                
                # Find M2Ms that have vanished
                for fieldname in old_m2ms:
                    if fieldname not in new_m2ms:
                        # Only delete its stuff if it wasn't a through=.
                        field = self.old_orm[key + ":" + fieldname]
                        if auto_through(field):
                            yield ("DeleteM2M", {"model": self.old_orm[key], "field": field})
                
                # Find M2Ms that have appeared
                for fieldname in new_m2ms:
                    if fieldname not in old_m2ms:
                        # Only create its stuff if it wasn't a through=.
                        field = self.current_field_from_key(key, fieldname)
                        if auto_through(field):
                            yield ("AddM2M", {"model": self.current_model_from_key(key), "field": field})
                
                # For the ones that exist in both models, see if they were changed
                for fieldname in set(old_fields).intersection(set(new_fields)):
                    # Non-index changes
                    if self.different_attributes(
                     remove_useless_attributes(old_fields[fieldname], True, True),
                     remove_useless_attributes(new_fields[fieldname], True, True)):
                        yield ("ChangeField", {
                            "model": self.current_model_from_key(key),
                            "old_field": self.old_orm[key + ":" + fieldname],
                            "new_field": self.current_field_from_key(key, fieldname),
                            "old_def": old_fields[fieldname],
                            "new_def": new_fields[fieldname],
                        })
                    # Index changes
                    old_field = self.old_orm[key + ":" + fieldname]
                    new_field = self.current_field_from_key(key, fieldname)
                    if not old_field.db_index and new_field.db_index:
                        # They've added an index.
                        yield ("AddIndex", {
                            "model": self.current_model_from_key(key),
                            "fields": [new_field],
                        })
                    if old_field.db_index and not new_field.db_index:
                        # They've removed an index.
                        yield ("DeleteIndex", {
                            "model": self.old_orm[key],
                            "fields": [old_field],
                        })
                    # See if their uniques have changed
                    if old_field.unique != new_field.unique:
                        # Make sure we look at the one explicitly given to see what happened
                        if new_field.unique:
                            yield ("AddUnique", {
                                "model": self.current_model_from_key(key),
                                "fields": [new_field],
                            })
                        else:
                            yield ("DeleteUnique", {
                                "model": self.old_orm[key],
                                "fields": [old_field],
                            })
                
                # See if there's any M2Ms that have changed.
                for fieldname in set(old_m2ms).intersection(set(new_m2ms)):
                    old_field = self.old_orm[key + ":" + fieldname]
                    new_field = self.current_field_from_key(key, fieldname)
                    # Have they _added_ a through= ?
                    if auto_through(old_field) and not auto_through(new_field):
                        yield ("DeleteM2M", {"model": self.old_orm[key], "field": old_field})
                    # Have they _removed_ a through= ?
                    if not auto_through(old_field) and auto_through(new_field):
                        yield ("AddM2M", {"model": self.current_model_from_key(key), "field": new_field})
                
                ## See if the {index,unique}_togethers have changed
                for attr, add_operation, del_operation in (("unique_together", "AddUnique", "DeleteUnique"), ("index_together", "AddIndex", "DeleteIndex")):
                    # First, normalise them into lists of sets.
                    old_together = eval(old_meta.get(attr, "[]"))
                    new_together = eval(new_meta.get(attr, "[]"))
                    if old_together and isinstance(old_together[0], string_types):
                        old_together = [old_together]
                    if new_together and isinstance(new_together[0], string_types):
                        new_together = [new_together]
                    old_together = frozenset(tuple(o) for o in old_together)
                    new_together = frozenset(tuple(n) for n in new_together)
                    # See if any appeared or disappeared
                    disappeared = old_together.difference(new_together)
                    appeared = new_together.difference(old_together)
                    for item in disappeared:
                        yield (del_operation, {
                            "model": self.old_orm[key],
                            "fields": [self.old_orm[key + ":" + x] for x in item],
                        })
                    for item in appeared:
                        yield (add_operation, {
                            "model": self.current_model_from_key(key),
                            "fields": [self.current_field_from_key(key, x) for x in item],
                        })
dataset/ETHPy150Open cloudera/hue/desktop/core/ext-py/South-1.0.2/south/creator/changes.py/AutoChanges.get_changes/swapped operands of `not in`