#24860: Migrations leak stale RelatedManager related_model definitions
------------------------------+---------------------------------------
     Reporter:  ecederstrand  |      Owner:  nobody
         Type:  Bug           |     Status:  new
    Component:  Migrations    |    Version:  1.8
     Severity:  Normal        |   Keywords:  migration, RelatedManager
 Triage Stage:  Unreviewed    |  Has patch:  0
Easy pickings:  0             |      UI/UX:  0
------------------------------+---------------------------------------
 I have a Django 1.8.2 app with models A and B, where data in class A has
 been migrated from one field to another. My actual code is a lot more
 involved and difficult to reduce to a sane test case, but the following is
 the essence of my debugging:

 {{{
 # Unchanged
 class B(models.Model):
    pass


 # version 1
 class A(models.Model):
    b = models.ForeignKey(B)
    x = models.FooField()
 }}}

 Now field 'y' is added to class A and a migration is created

 {{{
 # version 2
 class A(models.Model):
    rel = models.ForeignKey(B)
    x = models.FooField()
    y = models.BarField()
 }}}

 A data migration to move data from 'x' to 'y' is created

 {{{
    A = apps.get_model("my_app", "A")
    for i in A.objects.all():
       i.y = i.x
       i.save()
 }}}

 Field 'x' is no longer needed on class A. New migration is created

 {{{
 # version 3
 class A(models.Model):
    rel = models.ForeignKey(B)
    y = models.BarField()
 }}}

 Now when I run a test case which uses prefetch, invalid SQL is generated.

 {{{
 def test_case():
     list(B.objects.all().prefetch_related('a_set'))
 ->  psycopg2.ProgrammingError: column A.x does not exist
 }}}


 The reason for this is that 'def related_manager_cls()' in
 django/db/models/fields/related.py:832 is a @cached_property. When I run
 my test case, the migrations are run to create the test database. This
 caches version 2 of class A in self.related.related_model as a <class
 '__fake__.A'>, which is then returned later on in the test case. Thus,
 prefetch SQL for version 2 is produced instead of for version 3. I suspect
 the problem occurs because of the data migration.

 No errors show when I use prefetch_related() in production, because the
 migrations aren't run.

 I'm uncertain how to fix this. Somehow the property caches should be
 invalidated after each migration is run.

 It seems related.py has more potentally dangerous uses of @cached_property

--
Ticket URL: <https://code.djangoproject.com/ticket/24860>
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 django-updates+unsubscr...@googlegroups.com.
To post to this group, send email to django-updates@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/055.12f4b19126f96b2e0834db942da1eab3%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to