Setup:
- 2 models (A and B)
- B has a OneToOne to A
- Both A and B have a field (ie TextField)
- Setup either a signal or override save() for A to update B's TextField
to equal that of A's on save() or post_save for signals
Steps:
- Create instance of A
- Get another copy of the instance of A via A.objects.get()
- Create instance of B using the copy of the instance of A
- Do refresh_from_db() on original instance of A
- Try to access B from A
The project I have provided is a slim version of this problem that
demonstrates it with signals, overriden save(), and basic set and save
inside the test. The basic set and save works, but the other two fail when
using the above steps.
--
Ticket URL: <https://code.djangoproject.com/ticket/27846>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* Attachment "django_1_10_refresh_from_db_bug.rar" added.
* type: Uncategorized => Bug
--
Ticket URL: <https://code.djangoproject.com/ticket/27846#comment:1>
Old description:
> Sorry for the poor summary, it is difficult to explain in words. I have a
> project to demo this bug attached to this ticket, but I will try to
> explain the bug anyway in steps and the setup.
>
> Setup:
> - 2 models (A and B)
> - B has a OneToOne to A
> - Both A and B have a field (ie TextField)
> - Setup either a signal or override save() for A to update B's TextField
> to equal that of A's on save() or post_save for signals
>
> Steps:
> - Create instance of A
> - Get another copy of the instance of A via A.objects.get()
> - Create instance of B using the copy of the instance of A
> - Do refresh_from_db() on original instance of A
> - Try to access B from A
>
> The project I have provided is a slim version of this problem that
> demonstrates it with signals, overriden save(), and basic set and save
> inside the test. The basic set and save works, but the other two fail
> when using the above steps.
New description:
Sorry for the poor summary, it is difficult to explain in words. I have a
project to demo this bug attached to this ticket, but I will try to
explain the bug anyway in steps and the setup.
Setup:
- 2 models (A and B)
- B has a OneToOne to A
- Both A and B have a field (ie TextField)
- Setup either a signal or override save() for A to update B's TextField
to equal that of A's on save() or post_save for signals
Steps:
- Create instance of A
- Get another copy of the instance of A via A.objects.get()
- Create instance of B using the copy of the instance of A
- Do refresh_from_db() on original instance of A
- Try to access B from A
The project I have provided is a slim version of this problem that
demonstrates it with signals, overriden save(), and basic set and save
inside the test. The basic set and save works, but the other two fail when
using the above steps. Run the test suite to see.
--
--
Ticket URL: <https://code.djangoproject.com/ticket/27846#comment:2>
* stage: Unreviewed => Accepted
Comment:
I think this is fixable but I'm not sure without trying to write a patch.
This case may be discussed in ticket:901#comment:36 It looks like the
issue is that `refresh_from_db()`
[https://github.com/django/django/blob/a7214f0e84913a27e0b73de89d4c827ef1c53b94/django/db/models/base.py#L609-L620
clears concrete fields] but doesn't clear reverse relations.
--
Ticket URL: <https://code.djangoproject.com/ticket/27846#comment:3>
* owner: nobody => Matvey Kukuy
* status: new => assigned
--
Ticket URL: <https://code.djangoproject.com/ticket/27846#comment:4>
* status: assigned => new
* owner: Matvey Kukuy => (none)
--
Ticket URL: <https://code.djangoproject.com/ticket/27846#comment:5>
* owner: nobody => Paulo
* status: new => assigned
--
Ticket URL: <https://code.djangoproject.com/ticket/27846#comment:4>
* cc: Andrey Fedoseev (added)
--
Ticket URL: <https://code.djangoproject.com/ticket/27846#comment:5>
Comment (by Paulo):
Hello,
What do you all think about clearing the fields cache entirely on
refresh_from_db()?
This would cover similar bugs where a many to one or many to many
relationship is cached.
The only case we can't cover is fields prefetched to custom attributes.
--
Ticket URL: <https://code.djangoproject.com/ticket/27846#comment:6>
* cc: Berker Peksag (added)
--
Ticket URL: <https://code.djangoproject.com/ticket/27846#comment:7>
* has_patch: 0 => 1
Comment:
PR: https://github.com/django/django/pull/9112
--
Ticket URL: <https://code.djangoproject.com/ticket/27846#comment:8>
* status: assigned => closed
* resolution: => fixed
Comment:
In [changeset:"a7b5ad8b19a08d7d57302ece74f6e26d2887fd9f" a7b5ad8b]:
{{{
#!CommitTicketReference repository=""
revision="a7b5ad8b19a08d7d57302ece74f6e26d2887fd9f"
Fixed #27846 -- Made Model.refresh_from_db() clear cached relations.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/27846#comment:9>
Comment (by Tim Graham <timograham@…>):
In [changeset:"5d3f2aa3f12747822fb1ece95f0f614eeafa47b1" 5d3f2aa]:
{{{
#!CommitTicketReference repository=""
revision="5d3f2aa3f12747822fb1ece95f0f614eeafa47b1"
[2.0.x] Fixed #27846 -- Made Model.refresh_from_db() clear cached
relations.
Backport of a7b5ad8b19a08d7d57302ece74f6e26d2887fd9f from master
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/27846#comment:10>