Don't save CounterField values by default when saving models.

Review Request #9234 — Created Sept. 29, 2017 and submitted — Latest diff uploaded

Information

Djblets
release-0.10.x
e52e572...

Reviewers

We had a long-standing, hard-to-catch bug where counters would sometimes
end up with incorrect values, requiring a reset of the counters in order
to recompute. This turned out to be due to code
incrementing/decrementing a counter and then another instance somewhere
saving the old counter values back to the database.

The only time a counter's value should be included as part of a standard
save operation is if the value is being reset (saving None) or if it's
explicitly requested in update_fields.

While Django does allow for some control over which fields are saved to
the database, there's no way for fields themselves to opt out of saving
a value, which is what we'd prefer. So instead, CounterField now adds
a new version of _do_update() (the model's function that actually
kicks off computing the SQL to update a set of values) that filters out
the values first. This ensures that we never accidentally save a
CounterField or any of its subclasses.

Unit tests were added to check on this new behavior.

All Djblets and Review Board unit tests pass.

Manually tested with a solid repro case and saw that the old stale values
were no longer being stored during save().