toastdriven/django-tastypie — pull request #575 by dhatch (2012-07-17 21:35:39+00:00)
Title: [bugfix] Fixes m2m PUT

### Issue ###
When a *PUT* request is issued to a resource containing a m2m field, and that field already has existing data from the stored model, if the field is not included in the *PUT* data, its associated data will be erased from the model.

### Fix ###
The m2m data which exists in the database should be preserved unless the client explicitly sends an empty list for the m2m field in the *PUT* request.

### Cause ###
`hydrate_m2m` on `ToManyField`
```python
if bundle.data.get(self.instance_name) is None:
if self.blank:
return []
elif self.null:
return []
else:
raise ApiFieldError("The '%s' field has no data and doesn't allow a null value." % self.instance_name)
```

When no data is on the field, this if statement either returns an empty list for the value of the field (clearing its data) or raises an exception.

### Solution ###
1) Check that the object of the bundle is saved in the database (and thus can use m2m data), and that it has a manager on the attribute which contains data.
2) If this is true, `hydrate_m2m` returns `None`. This does not change the current handling of other request cases by the function because in this block, the client has already *PUT/POSTed* `None` (or no data) which would in the past have been interpreted as clearing the field.
3) In `save_m2m` check for `None` and skip clearing the m2m relation, leaving currently existing data intact.

### Result ###
m2m behavior is the same, except for when making a *PUT* request which does not include the m2m field in the data, or includes the field set to `null`

The patch includes appropriate modifications to the test suite for the new behavior.