def update(old, new, collection, sneaky_update_filter=None):
<EOL>need_save = False<EOL>locked_fields = old.get('<STR_LIT>', [])<EOL>for key, value in new.items():<EOL><INDENT>if key in locked_fields:<EOL><INDENT>continue<EOL><DEDENT>if old.get(key) != value:<EOL><INDENT>if sneaky_update_filter and key in sneaky_update_filter:<EOL><INDENT>if sneaky_update_filter[key](old[key], value):<EOL><INDENT>old[key] = value<EOL>need_save = True<EOL><DEDENT><DEDENT>else:<EOL><INDENT>old[key] = value<EOL>need_save = True<EOL><DEDENT><DEDENT>plus_key = '<STR_LIT>' % key<EOL>if plus_key in old:<EOL><INDENT>del old[plus_key]<EOL>need_save = True<EOL><DEDENT><DEDENT>if need_save:<EOL><INDENT>old['<STR_LIT>'] = datetime.datetime.utcnow()<EOL>collection.save(old, safe=True)<EOL><DEDENT>return need_save<EOL>
update an existing object with a new one, only saving it and
setting updated_at if something has changed

old
    old object
new
    new object
collection
    collection to save changed object to
sneaky_update_filter
    a filter for updates to object that should be ignored
    format is a dict mapping field names to a comparison function
    that returns True iff there is a change