MySQL 更新时未触发 Django/TastyPie REST API
MySQL On Update not triggering for Django/TastyPie REST API
我们有一个资源 table,它有一个字段 last_updated
,我们用 mysql-workbench 设置它具有以下属性:
数据类型:TIMESTAMP
NN (NotNull) 是 checked
默认:CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
当我通过 workbench 修改一行并应用它时,last_updated
字段会正确更新。
当我使用 REST api 时,我们已经设置并发出一个 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)
我可以正确更改任何值(包括状态和超时,并收到 204 响应),但 last_updated
没有更新。
Django's model documentation 表示在这种情况下它应该发送 UPDATE
.
有人知道为什么缺少这些更新吗?
我可以提供有关我们特定 Django/tastypie 设置的更多详细信息,但只要他们发出 UPDATE
,他们就应该触发数据库 ON UPDATE
.
我怀疑 Django 发出的 UPDATE 语句可能包含对 last_updated
列的赋值。这只是一个猜测,提供的信息不足。
但是如果 Django 模型包含 last_updated
列,并且该列是从数据库中提取到模型中的,我相信 save() 将分配一个UPDATE 语句中 last_updated
列的值。
https://docs.djangoproject.com/en/1.9/ref/models/instances/#specifying-which-fields-to-save
考虑我们发出如下 UPDATE 语句时的行为:
UPDATE mytable
SET last_updated = last_updated
, some_col = 'some_value'
WHERE id = 42
因为 UPDATE 语句正在为 last_updated
列赋值,所以不会自动赋值给 timestamp 列。语句中指定的值优先。
要自动分配给 last_updated
,必须从 SET
子句中省略该列,例如
UPDATE mytable
SET some_col = 'some_value'
WHERE id = 42
要调试它,您需要检查实际的 SQL 语句。
通过 spencer7593 的 添加的信息,我能够通过 tastypie 找到如何做到这一点:
BaseModelResource.save()
(来自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
需要在您的 class 中覆盖,以便您可以更改 Django save(),其中包含我们要修改的 update_fields
参数:
if obj_id not in bundle.objects_saved or bundle.obj._state.adding:
bundle.obj.save()
例如:
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)
# ...
这正确地从 sql UPDATE
中排除了 last_updated
列。
我们有一个资源 table,它有一个字段 last_updated
,我们用 mysql-workbench 设置它具有以下属性:
数据类型:TIMESTAMP
NN (NotNull) 是 checked
默认:CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
当我通过 workbench 修改一行并应用它时,last_updated
字段会正确更新。
当我使用 REST api 时,我们已经设置并发出一个 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)
我可以正确更改任何值(包括状态和超时,并收到 204 响应),但 last_updated
没有更新。
Django's model documentation 表示在这种情况下它应该发送 UPDATE
.
有人知道为什么缺少这些更新吗?
我可以提供有关我们特定 Django/tastypie 设置的更多详细信息,但只要他们发出 UPDATE
,他们就应该触发数据库 ON UPDATE
.
我怀疑 Django 发出的 UPDATE 语句可能包含对 last_updated
列的赋值。这只是一个猜测,提供的信息不足。
但是如果 Django 模型包含 last_updated
列,并且该列是从数据库中提取到模型中的,我相信 save() 将分配一个UPDATE 语句中 last_updated
列的值。
https://docs.djangoproject.com/en/1.9/ref/models/instances/#specifying-which-fields-to-save
考虑我们发出如下 UPDATE 语句时的行为:
UPDATE mytable
SET last_updated = last_updated
, some_col = 'some_value'
WHERE id = 42
因为 UPDATE 语句正在为 last_updated
列赋值,所以不会自动赋值给 timestamp 列。语句中指定的值优先。
要自动分配给 last_updated
,必须从 SET
子句中省略该列,例如
UPDATE mytable
SET some_col = 'some_value'
WHERE id = 42
要调试它,您需要检查实际的 SQL 语句。
通过 spencer7593 的
BaseModelResource.save()
(来自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
需要在您的 class 中覆盖,以便您可以更改 Django save(),其中包含我们要修改的 update_fields
参数:
if obj_id not in bundle.objects_saved or bundle.obj._state.adding:
bundle.obj.save()
例如:
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)
# ...
这正确地从 sql UPDATE
中排除了 last_updated
列。