[autotest] Serialize foreign key we don't want to follow
In some case, we don't want to follow a relationship when
serialize and de-serialize an object. However, we may
want to serialize the value of the foreign key value.
For example, we follow Host.hostattribute_set relationship to
serialize HostAttribute objects associated with a host. We
don't want to follow HostAttribute.host_id to go back to Host.
This CL allows a model to claim foreign keys that will be
serialized but will not be followed.
BUG=None
TEST=In python
>>> import common
>>> from autotest_lib.frontend import setup_django_environment
>>> from autotest_lib.frontend.afe import models
>>> models.HostAttribute.objects.filter(host_id=20)[0].serialize()
{'host_id': 20L, u'id': 203L, 'value': u'2271', 'attribute':
u'need_crash_log'}
>>> models.HostAttribute.deserialize({'host_id': 20L, u'id': 251L,
'value': u'2271', 'attribute': u'need_crash_log'})
<HostAttribute: HostAttribute object>
TEST=Test shard heartbeat works when host attributes present.
DEPLOY=apache, shard_client
Change-Id: I8e0fbb1b7eb037f0968c1599334446301ddbbcb0
Reviewed-on: https://chromium-review.googlesource.com/236708
Reviewed-by: Fang Deng <fdeng@chromium.org>
Tested-by: Fang Deng <fdeng@chromium.org>
Reviewed-by: Prashanth B <beeps@chromium.org>
Tested-by: Prashanth B <beeps@chromium.org>
Commit-Queue: Prashanth B <beeps@chromium.org>
Trybot-Ready: Prashanth B <beeps@chromium.org>
diff --git a/frontend/afe/model_logic.py b/frontend/afe/model_logic.py
index 5781646..a0923ba 100644
--- a/frontend/afe/model_logic.py
+++ b/frontend/afe/model_logic.py
@@ -2,8 +2,6 @@
Extensions to Django's model logic.
"""
-import re
-import time
import django.core.exceptions
from django.db import backend
from django.db import connection
@@ -531,6 +529,14 @@
"""
+ SERIALIZATION_LINKS_TO_KEEP = set()
+ """This set stores foreign keys which we don't want to follow, but
+ still want to include in the serialized dictionary. For
+ example, we follow the relationship `Host.hostattribute_set`,
+ but we do not want to follow `HostAttributes.host_id` back to
+ to Host, which would otherwise lead to a circle. However, we still
+ like to serialize HostAttribute.`host_id`."""
+
SERIALIZATION_LOCAL_LINKS_TO_UPDATE = set()
"""
On deserializion, if the object to persist already exists, local fields
@@ -938,6 +944,12 @@
for field in self._meta.concrete_model._meta.local_fields:
if field.rel is None:
serialized[field.name] = field._get_val_from_obj(self)
+ elif (include_dependencies and
+ field.name in self.SERIALIZATION_LINKS_TO_KEEP):
+ # attname will contain "_id" suffix for foreign keys,
+ # e.g. HostAttribute.host will be serialized as 'host_id'.
+ # Use it for easy deserialization.
+ serialized[field.attname] = field._get_val_from_obj(self)
if include_dependencies:
for link in self.SERIALIZATION_LINKS_TO_FOLLOW:
@@ -984,7 +996,8 @@
# It's a foreign key
links_to_related_values.append((link, value))
else:
- # It's a local attribute
+ # It's a local attribute or a foreign key
+ # we don't want to follow.
links_to_local_values.append((link, value))
return links_to_local_values, links_to_related_values