Opened 9 years ago

Closed 9 years ago

Last modified 9 years ago

#24808 closed Bug (duplicate)

An error that occurs when 2 migrations happen to execute as the result of a single migrate command.

Reported by: damix911 Owned by: nobody
Component: Migrations Version: 1.8
Severity: Normal Keywords: migrations
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

I'm using Python 3.4.2 and Django 1.8 and 1.8.1. The problem systematically occurs only with Django 1.8 but the 1.8.1 (or 1.8.2) release notes don't mention the presence of such a bug so I think I should describe my experience to the community anyway.

models.py:

from django.db import models

class Parent(models.Model):
    pass

class RelatedA(models.Model):
    parent = models.ForeignKey('Parent')
    
class RelatedB(models.Model):
    parent = models.ForeignKey('Parent')

A custom data migration 0002_populate.py used to populate the DB with some initial data:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

def populate(apps, schema_editor):
    Parent = apps.get_model("foo", "Parent")
    
    if not Parent.objects.filter().exists():
        p = Parent()
        p.save()

        RelatedX = apps.get_model("foo", <<<either "RelatedA" or "RelatedB">>>)
        
        if not RelatedX.objects.filter(parent = p).exists():
            print("\n ********** :-) :-) :-) **********\n")
    
class Migration(migrations.Migration):

    dependencies = [
        ('foo', '0001_initial'),
    ]

    operations = [
        migrations.RunPython(populate)
    ]

Line 13 of the data migration has been tested like this:

RelatedX = apps.get_model("foo", "RelatedA")

And like this:

RelatedX = apps.get_model("foo", "RelatedB")

In Django 1.8 and 1.8.1; this gives rise to 4 different tests:

  • proj180a: Uses Django 1.8 and imports "RelatedA"
  • proj180b: Uses Django 1.8 and imports "RelatedB"
  • proj181a: Uses Django 1.8.1 and imports "RelatedA"
  • proj181b: Uses Django 1.8.1 and imports "RelatedB"

The test involves running the command:

python manage.py migrate

When the SQLite database still doesn't exist.

The results are as follows:

  • proj180a: Fails on first run, succeeds if python manage.py migrate is run again.
  • proj180b: Pass.
  • proj181a: Pass.
  • proj181b: Pass.

The failure of proj180a is as follows:

  File "C:\Users\dario\Desktop\Repos\Programming\Django\Varie\venv-34-180\lib\site-packages\django\db\models\sql\query.py", line 1170, in build_filter
    self.check_related_objects(field, value, opts)
  File "C:\Users\dario\Desktop\Repos\Programming\Django\Varie\venv-34-180\lib\site-packages\django\db\models\sql\query.py", line 1068, in check_related_objects
    self.check_query_object_type(value, opts)
  File "C:\Users\dario\Desktop\Repos\Programming\Django\Varie\venv-34-180\lib\site-packages\django\db\models\sql\query.py", line 1052, in check_query_object_type
    (value, opts.object_name))
ValueError: Cannot query "Parent object": Must be "Parent" instance.

If the DB exists and migration 0001_initial.py has already been applied then also the proj180a test passes on the first run. I'm attaching the full output (obviously with stderr included) of three consecutive runs of migrate.

In synthesis, there seems to be a problem with chaining migrations in a single migrate command (which should be a fairly typical case). Why this happens with RelatedA and not with RelatedB is beyond me, but must have something to do with the order in which the models are declared in models.py.

I'm attaching an archive with four projects; two for Django 1.8 and two for Django 1.8.1. To reproduce the issue you should use a virtualenv with Diango 1.8 to migrate proj180a and proj180b and a virtualenv with Django 1.8.1 to migrate proj181a and proj181b.

Finally, I should mention that I derived the discussed SSCCEs from the code of a real application I'm working on.

In my application the role of Parent and RelatedA is played by Organization and Link (my application is a CMS that can serve multiple independent organizations, and specifically each one of them can mantain its own set of links to other resources and pages).

In the real thing, the line that causes problems is:

if not Link.objects.filter(organization = organization, slug = slug).exists():

Which results in the following error (like proj180a) on the first migrate run.

ValueError: Cannot query "Organization object": Must be "Organization" instance.

It is interesting to note that using related managers doesn't solve the issue (actually, I discovered the bug while using RMs, but then I learned that RMs can create problems in migrations, so I opted for the joint condition filter).

However the error message is not the same, and also in this case the second migrate runs fine.

if not organization.link_set.filter(slug = slug).exists():

Results in:

AttributeError: 'Organization' object has no attribute 'link_set'

Attachments (1)

Tests.zip (37.8 KB ) - added by damix911 9 years ago.
4 different test cases, plus the output of the one that fails.

Download all attachments as: .zip

Change History (3)

by damix911, 9 years ago

Attachment: Tests.zip added

4 different test cases, plus the output of the one that fails.

comment:1 by Claude Paroz, 9 years ago

Resolution: invalid
Status: newclosed

Should we assume from your report that the problem cannot be reproduced on Django 1.8.1? If it's the case, then why bother? Sorry if I misunderstood the issue.

comment:2 by Markus Holtermann, 9 years ago

Resolution: invalidduplicate

For the record, this sounds like #24573 and has been fixed in 1.8.1 and is properly addressed in the release notes.

Note: See TracTickets for help on using tickets.
Back to Top