Opened 9 years ago

Closed 9 years ago

Last modified 9 years ago

#23738 closed Bug (fixed)

Migrations broken with django 1.7.1 when changing null from true to false.

Reported by: Andrey Antukh Owned by: Markus Holtermann
Component: Migrations Version: 1.7
Severity: Release blocker Keywords:
Cc: info+coding@… Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Hi!

I start having strange exceptions when I have migrated a project from django 1.7 to 1.7.1

(taiga)[3/5.0.7]{1}niwi@niwi:~/taiga/taiga-back> python manage.py sqlmigrate projects 0006
Traceback (most recent call last):
  File "manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/home/niwi/.virtualenvs/taiga/lib/python3.4/site-packages/Django-1.7.2.dev20141030224451-py3.4.egg/django/core/management/__init__.py", line 385, in execute_from_command_line
    utility.execute()
  File "/home/niwi/.virtualenvs/taiga/lib/python3.4/site-packages/Django-1.7.2.dev20141030224451-py3.4.egg/django/core/management/__init__.py", line 377, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/home/niwi/.virtualenvs/taiga/lib/python3.4/site-packages/Django-1.7.2.dev20141030224451-py3.4.egg/django/core/management/base.py", line 288, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "/home/niwi/.virtualenvs/taiga/lib/python3.4/site-packages/Django-1.7.2.dev20141030224451-py3.4.egg/django/core/management/commands/sqlmigrate.py", line 30, in execute
    return super(Command, self).execute(*args, **options)
  File "/home/niwi/.virtualenvs/taiga/lib/python3.4/site-packages/Django-1.7.2.dev20141030224451-py3.4.egg/django/core/management/base.py", line 338, in execute
    output = self.handle(*args, **options)
  File "/home/niwi/.virtualenvs/taiga/lib/python3.4/site-packages/Django-1.7.2.dev20141030224451-py3.4.egg/django/core/management/commands/sqlmigrate.py", line 61, in handle
    sql_statements = executor.collect_sql(plan)
  File "/home/niwi/.virtualenvs/taiga/lib/python3.4/site-packages/Django-1.7.2.dev20141030224451-py3.4.egg/django/db/migrations/executor.py", line 77, in collect_sql
    migration.apply(project_state, schema_editor, collect_sql=True)
  File "/home/niwi/.virtualenvs/taiga/lib/python3.4/site-packages/Django-1.7.2.dev20141030224451-py3.4.egg/django/db/migrations/migration.py", line 108, in apply
    operation.database_forwards(self.app_label, schema_editor, project_state, new_state)
  File "/home/niwi/.virtualenvs/taiga/lib/python3.4/site-packages/Django-1.7.2.dev20141030224451-py3.4.egg/django/db/migrations/operations/fields.py", line 139, in database_forwards
    schema_editor.alter_field(from_model, from_field, to_field)
  File "/home/niwi/.virtualenvs/taiga/lib/python3.4/site-packages/Django-1.7.2.dev20141030224451-py3.4.egg/django/db/backends/schema.py", line 473, in alter_field
    self._alter_field(model, old_field, new_field, old_type, new_type, old_db_params, new_db_params, strict)
  File "/home/niwi/.virtualenvs/taiga/lib/python3.4/site-packages/Django-1.7.2.dev20141030224451-py3.4.egg/django/db/backends/schema.py", line 617, in _alter_field
    sql, params = tuple(zip(*actions))
ValueError: need more than 0 values to unpack

I start research.

Firstly I have surprised that the last created migration does not include null=False change: https://github.com/taigaio/taiga-back/blob/improvements-migrations/taiga/projects/migrations/0006_auto_20141029_1040.py but this, more surprisingly with django 1.7 emits correct sql migration without having null=False in a migration file:

(taiga)[3/5.0.7]niwi@niwi:~/taiga/taiga-back> python manage.py sqlmigrate projects 0006
BEGIN;
--
-- MIGRATION NOW PERFORMS OPERATION THAT CANNOT BE WRITTEN AS SQL:
-- Raw Python operation
--
ALTER TABLE "projects_project" ALTER COLUMN "total_milestones" SET NOT NULL;
ALTER TABLE "projects_project" ALTER COLUMN "total_milestones" DROP DEFAULT;

COMMIT;

This is a proper behavior?

But with django 1.7.1 it seems not detects correctly the null attribute change, that causes that actions variable on django/db/backends/schema.py:617 to be empty, which in turn, causes that exception.

I have tried set manually the null=False parameter on the migrations file, and it no such effect (works with django 1.7 and raises exception with django 1.7.1)

Change History (12)

comment:1 by Tim Graham, 9 years ago

Did you generate the migration with Django 1.7 or 1.7.1? If the former, could you try regenerating it with 1.7.1? I think #23609 (fixed in 1.7.1) could be related.

comment:2 by Andrey Antukh, 9 years ago

The migration is generated by django 1.7 but I have tried generate it with django 1.7.1, but it no such effect. The same exception is raised and the same behavior on creating the migration file (missing null=True and blank=True on alterfield action).

Also, I have tried with 1.7.2dev (stable/1.7.x branch) and also I have found the same exception.

comment:3 by Tim Graham, 9 years ago

I've having trouble reproducing the issue. Could you outline the minimal steps (ideally one that doesn't involve a big project like the example you linked)? Not sure it matters, but which database backend are you using?

comment:4 by Andrey Antukh, 9 years ago

We are using the psycopg2 backend.

Tomorrow I'll try to make a small project for make easy to reproduce it.

But the process is very simple:

  • havind django 1.7, I have created a migration to one model that already have one integer field with null=True, blank=True and default=0 on first migration, changing null and blank parameters both to False.
  • update to django 1.7.1
  • try apply the created migration

comment:5 by Markus Holtermann, 9 years ago

Cc: info+coding@… added

I can confirm the problem

comment:6 by Markus Holtermann, 9 years ago

Owner: changed from nobody to Markus Holtermann
Status: newassigned

comment:7 by Tim Graham, 9 years ago

Severity: NormalRelease blocker
Triage Stage: UnreviewedAccepted

comment:8 by Markus Holtermann, 9 years ago

I opened a pull-request to fix this ticket: https://github.com/django/django/pull/3452

comment:9 by Markus Holtermann, 9 years ago

As long as you don't have a high traffic site, you should get it working with the following workaround:

class Migration(migrations.Migration):
    dependencies = [
        # your dependencies here
    ]

    operations = [
        migrations.AlterField(
            model_name='mymodel',
            name='myfield',
            field=models.IntegerField(null=True, blank=True, default=None),
        ),
        migrations.AlterField(
            model_name='mymodel',
            name='myfield',
            field=models.IntegerField(default=0),
        ),
    ]

What happened: Unfortunately I didn't took into account in the other patch that the default sticks between a NULL and NOT NULL change :-/. Thus changing the default from e.g. 0 to NULL while sticking to the NULL constraint and changing it back to 0 together with adding the NOT NULL constraint should work.

comment:10 by Andrey Antukh, 9 years ago

Thanks for this workaround. In our case that is not very problematic and we are reverted temporally to django 1.7.

Thanks for the quick fix.

comment:11 by Tim Graham <timograham@…>, 9 years ago

Resolution: fixed
Status: assignedclosed

In 715ccfde24f9f2b7f6710429370a1eff3c78fc2a:

Fixed #23738 -- Allowed migrating from NULL to NOT NULL with the same default value

Thanks to Andrey Antukh for the report.

comment:12 by Tim Graham <timograham@…>, 9 years ago

In 40ad022d5e366f56424dcdb885607d13c00a550e:

[1.7.x] Fixed #23738 -- Allowed migrating from NULL to NOT NULL with the same default value

Thanks to Andrey Antukh for the report.

Backport of 715ccfde24 from master

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