use _dirty.discard, not _dirty.remove

In the case where the field has not actually changed, don't throw a KeyError;
just proceed silently.
clean up some string formatting