#34137: model.refresh_from_db() doesn't seem to clear cached generic foreign 
keys
--------------------------------+--------------------------------------
     Reporter:  pascal chambon  |                    Owner:  nobody
         Type:  Uncategorized   |                   Status:  new
    Component:  Uncategorized   |                  Version:  3.2
     Severity:  Normal          |               Resolution:
     Keywords:                  |             Triage Stage:  Unreviewed
    Has patch:  0               |      Needs documentation:  0
  Needs tests:  0               |  Patch needs improvement:  0
Easy pickings:  0               |                    UI/UX:  0
--------------------------------+--------------------------------------
Description changed by pascal chambon:

Old description:

> In my code, Users have a generic foreign key like so:
>
> {{{
>     controlled_entity_content_type = models.ForeignKey(ContentType,
> blank=True, null=True, on_delete=models.CASCADE)
>     controlled_entity_object_id = models.PositiveIntegerField(blank=True,
> null=True)
>     controlled_entity =
> GenericForeignKey("controlled_entity_content_type",
> "controlled_entity_object_id")
> }}}
>
> However, in unit-tests, when I refresh a user instance, the
> controlled_entity relation isn't cleared from cache, as can be seen here
> with IDs:
>

> {{{
>         old_controlled_entity = authenticated_user.controlled_entity
>         authenticated_user.refresh_from_db()
>         new_controlled_entity = authenticated_user.controlled_entity
>         assert id(old_controlled_entity) != id(new_controlled_entity)   #
> FAILS
> }}}
>

> And this leads to subtle bugs like non-transitive equalities in tests :
>

> {{{
>         assert authenticated_user.controlled_entity ==
> fixtures.client1_project2_organization3
>         assert fixtures.client1_project2_organization3.get_pricing_plan()
> == pricing_plan
>         assert authenticated_user.controlled_entity.get_pricing_plan() ==
> pricing_plan     # FAILS
> }}}
>
> Calling "authenticated_user.controlled_entity.refresh_from_db()" solevd
> this particular bug, but "authenticated_user.refresh_from_db()" isn't
> enough.
>

> Tested under Django3.2.13 but the code of refresh_from_db() hasn't
> changed since then in Git's main branch (except few cosmetic adjustments
> on code format).
>
> I'm a bit lost in the code of refresh_from_db(), but I've just seen that
> the generic relation appears once in this loop, but is not considered as
> "cached" in the if() branch.
>
> {{{
>         for field in self._meta.related_objects:
>             #print("%% CLEARING RELATED FIELD", field)
>             if field.is_cached(self):
>                 #print("%% DONE")   # not called
>                 field.delete_cached_value(self)
> }}}

New description:

 In my code, Users have a generic foreign key like so:

 {{{
     controlled_entity_content_type = models.ForeignKey(ContentType,
 blank=True, null=True, on_delete=models.CASCADE)
     controlled_entity_object_id = models.PositiveIntegerField(blank=True,
 null=True)
     controlled_entity =
 GenericForeignKey("controlled_entity_content_type",
 "controlled_entity_object_id")
 }}}

 However, in unit-tests, when I refresh a user instance, the
 controlled_entity relation isn't cleared from cache, as can be seen here
 with IDs:


 {{{
         old_controlled_entity = authenticated_user.controlled_entity
         authenticated_user.refresh_from_db()
         new_controlled_entity = authenticated_user.controlled_entity
         assert id(old_controlled_entity) != id(new_controlled_entity)   #
 FAILS
 }}}


 And this leads to subtle bugs like non-transitive equalities in tests :


 {{{
         assert authenticated_user.controlled_entity ==
 fixtures.client1_project2_organization3
         assert fixtures.client1_project2_organization3.get_pricing_plan()
 == pricing_plan
         assert authenticated_user.controlled_entity.get_pricing_plan() ==
 pricing_plan     # FAILS
 }}}

 Calling "authenticated_user.controlled_entity.refresh_from_db()" solved
 this particular bug, but "authenticated_user.refresh_from_db()" isn't
 enough.


 Tested under Django3.2.13 but the code of refresh_from_db() hasn't changed
 since then in Git's main branch (except few cosmetic adjustments on code
 format).

 I'm a bit lost in the code of refresh_from_db(), but I've just seen that
 the generic relation appears once in this loop, but is not considered as
 "cached" in the if() branch.

 {{{
         for field in self._meta.related_objects:
             #print("%% CLEARING RELATED FIELD", field)
             if field.is_cached(self):
                 #print("%% DONE")   # not called
                 field.delete_cached_value(self)
 }}}

--

-- 
Ticket URL: <https://code.djangoproject.com/ticket/34137#comment:1>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/010701843d45671b-03565bc9-1dc9-4d19-a754-8a61caa74968-000000%40eu-central-1.amazonses.com.

Reply via email to