Remove cached value of reverse side of 020 relation when updating attname.
Repro:
from django.db import models
class AppUser(models.Model):
pass
class Profile(models.Model):
user = models.OneToOneField(
to=AppUser,
on_delete=models.PROTECT,
)
a = AppUser.objects.create()
b = AppUser.objects.create()
Profile.objects.create(user=a)
b.profile # Errors, since it has not been created yet
a.profile.user_id = b.id
a.profile.save()
# Works!
Profile.objects.get(user=b)
# <Profile: Profile object (1)>
b.profile # Errors, since it uses the cached value
I can fix it by using a.profile.user = b
instead of a.profile.user_id = b.id
which does the cache invalidation as expected. Or using b.refresh_from_db()
after the save()
call. However I think it makes sense to fix this within the ORM because it's a subtle bug that can cause issues.
This is a contrived example but the real use-case was cloning a model instance. And instead of erroring it just kept returning the cached value
Change History
(6)
Description: |
modified (diff)
|
Description: |
modified (diff)
|
Description: |
modified (diff)
|
Type: |
Uncategorized → Bug
|
Component: |
Uncategorized → Database layer (models, ORM)
|
Summary: |
Inconsistent related field cache invalidation → Remove cached value of reverse side of 020 relation when updating attname.
|
Triage Stage: |
Unreviewed → Accepted
|
Thanks for this ticket, I can see inconsistency but I'm not sure if it's feasible. Tentatively accepting for investigation.
The main difference is that
profile.user = b
uses one-to-one descriptors and has access to both side instances, on the other handprofile.user_id = b.id
uses a deferred attribute.This is probably fixed by #31863.