Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Django Upgrade] [ENG-4072] The Rest - Part 2 #10072

Merged
18 changes: 14 additions & 4 deletions osf/models/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,20 @@ def reload(self):

def refresh_from_db(self, **kwargs):
super(BaseModel, self).refresh_from_db(**kwargs)
# Django's refresh_from_db does not uncache GFKs
for field in self._meta.private_fields:
if hasattr(field, 'cache_attr') and field.cache_attr in self.__dict__:
del self.__dict__[field.cache_attr]
Comment on lines -111 to -114
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • private_fields is not GFK though GFK seems to be in private_fields
  • Since Django 2.2, any cached relations are cleared from the reloaded instance

# Since Django 2.2, any cached relations are cleared from the reloaded instance.
# See https://docs.djangoproject.com/en/2.2/ref/models/instances/#django.db.models.Model.refresh_from_db
# However, the default `refresh_from_db()` doesn't refresh related fields. Neither can we refresh related
# field(s) since it will inevitably cause infinite loop; and Many/One-to-Many relations add to the complexity.
# The recommended behavior is to explicitly refresh the fields when necessary. In order to preserve pre-upgrade
# behavior, our customization only reloads GFKs.
for f in self._meta._get_fields(reverse=False):
# Note: the following `if` condition is how django internally identifies GFK
if f.is_relation and f.many_to_one and not (hasattr(f.remote_field, 'model') and f.remote_field.model):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only refresh GFK, which is many_to_one and thus won't cause infinite loop.

if hasattr(self, f.name):
try:
getattr(self, f.name).refresh_from_db()
except AttributeError:
continue

def clone(self):
"""Create a new, unsaved copy of this object."""
Expand Down