Reputation: 7952
We have a resource table which has a field last_updated
which we setup with mysql-workbench to have the following properties:
Datatype: TIMESTAMP
NN (NotNull) is checked
Default: CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
When I modify a row through the workbench and apply it, the last_updated
field properly updates.
When I use the REST api we've setup, and issue a put:
update = requests.put('http://127.0.0.1:8000/api/resources/16',
data=json.dumps(dict(status="/api/status/4", timeout=timeout_time)),
headers=HEADER)
I can properly change any of the values (including status and timeout, and receive a 204 response), but last_updated
does not update.
Django's model documentation says in this case it should be sending an UPDATE
.
Anyone have and ideas on why it's missing these updates?
I can provide further details regarding our specific Django/tastypie setup, but as long as they are issuing an UPDATE
, they should be triggering the databases ON UPDATE
.
Upvotes: 0
Views: 180
Reputation: 7952
With the added information from spencer7593's answer, I was able to track down how to do this through tastypie:
The BaseModelResource.save()
(from tastypie/resources.py
):
def save(self, bundle, skip_errors=False):
if bundle.via_uri:
return bundle
self.is_valid(bundle)
if bundle.errors and not skip_errors:
raise ImmediateHttpResponse(response=self.error_response(bundle.request, bundle.errors))
# Check if they're authorized.
if bundle.obj.pk:
self.authorized_update_detail(self.get_object_list(bundle.request), bundle)
else:
self.authorized_create_detail(self.get_object_list(bundle.request), bundle)
# Save FKs just in case.
self.save_related(bundle)
# Save the main object.
obj_id = self.create_identifier(bundle.obj)
if obj_id not in bundle.objects_saved or bundle.obj._state.adding:
bundle.obj.save()
bundle.objects_saved.add(obj_id)
# Now pick up the M2M bits.
m2m_bundle = self.hydrate_m2m(bundle)
self.save_m2m(m2m_bundle)
return bundle
Needs to be overridden in your class, so that you can change the Django save(), which has the update_fields
parameter we want to modify:
if obj_id not in bundle.objects_saved or bundle.obj._state.adding:
bundle.obj.save()
To, for example:
class ResourcesResource(ModelResource):
# ...
def save(self, bundle, skip_errors=False):
# ...
if obj_id not in bundle.objects_saved or bundle.obj._state.adding:
resource_fields = [field.name for field in Resources._meta.get_fields()
if not field.name in ['id', 'last_updated']]
bundle.obj.save(update_fields=resource_fields)
# ...
This properly excludes the last_updated
column from the sql UPDATE
.
Upvotes: 0
Reputation: 108480
I suspect that the UPDATE statement issued by Django may be including an assignment to the last_updated
column. This is just a guess, there's not enough information provided.
But if the Django model contains the last_updated
column, and that column is fetched from the database into the model, I believe a save() will assign a value to the last_updated
column, in the UPDATE statement.
https://docs.djangoproject.com/en/1.9/ref/models/instances/#specifying-which-fields-to-save
Consider the behavior when we issue an UPDATE statement like this:
UPDATE mytable
SET last_updated = last_updated
, some_col = 'some_value'
WHERE id = 42
Because the UPDATE statement is assigning a value to the last_updated
column, the automatic assignment to the timestamp column won't happen. The value assigned in the statement takes precedence.
To get the automatic assignment to last_updated
, that column has to be omitted from the SET
clause, e.g.
UPDATE mytable
SET some_col = 'some_value'
WHERE id = 42
To debug this, you'd want to inspect the actual SQL statement.
Upvotes: 1