#20978 closed Bug (fixed)
Cannot migrate if on_delete=models.SET_NULL
Reported by: | Markus Holtermann | Owned by: | loic84 |
---|---|---|---|
Component: | Migrations | Version: | dev |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Accepted | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Given the following models, the migrate
step fails with 'module' object has no attribute 'set_on_delete'
.
# -*- coding: utf-8 -*- from django.db import models from django.utils.encoding import python_2_unicode_compatible @python_2_unicode_compatible class MyModel(models.Model): name = models.CharField('Name', max_length=50, unique=True) text = models.TextField('Text', blank=True, null=True) class Meta: verbose_name = 'My “fancy” Model' verbose_name_plural = 'My “fancy” Models' def __str__(self): return self.name @python_2_unicode_compatible class OtherModel(models.Model): mymodel = models.ForeignKey(MyModel, null=True, on_delete=models.SET_NULL) value = models.IntegerField('Value', blank=True, null=False, default=50) class Meta: verbose_name = 'Other Model' verbose_name_plural = 'Other Models' def __str__(self): return '%(mymodel)s %(value)d' % { 'mymodel': self.mymodel.name, 'value': self.value, }
The migration file looks like
# encoding: utf8 from django.db import models, migrations import django.db.models.deletion class Migration(migrations.Migration): dependencies = [(u'something', '0001_initial')] operations = [ migrations.CreateModel( fields = [(u'id', models.AutoField(verbose_name=u'ID', serialize=False, auto_created=True, primary_key=True),), ('name', models.CharField(unique=True, max_length=50, verbose_name='Name'),), ('text', models.TextField(null=True, verbose_name='Text', blank=True),)], bases = (models.Model,), options = {u'verbose_name': 'My \xe2\x80\x9cfancy\xe2\x80\x9d Model', u'verbose_name_plural': 'My \xe2\x80\x9cfancy\xe2\x80\x9d Models'}, name = 'MyModel', ), migrations.CreateModel( fields = [(u'id', models.AutoField(verbose_name=u'ID', serialize=False, auto_created=True, primary_key=True),), ('mymodel', models.ForeignKey(to=u'something.MyModel', to_field=u'id', null=True, on_delete=django.db.models.deletion.set_on_delete),), ('value', models.IntegerField(default=50, verbose_name='Value', blank=True),)], bases = (models.Model,), options = {u'verbose_name': 'Other Model', u'verbose_name_plural': 'Other Models'}, name = 'OtherModel', ), ]
Migrating with Python 3.3:
Traceback (most recent call last): File "manage.py", line 10, in <module> execute_from_command_line(sys.argv) File "/home/markus/.venvs/django-master-py3/src/django/django/core/management/__init__.py", line 397, in execute_from_command_line utility.execute() File "/home/markus/.venvs/django-master-py3/src/django/django/core/management/__init__.py", line 390, in execute self.fetch_command(subcommand).run_from_argv(self.argv) File "/home/markus/.venvs/django-master-py3/src/django/django/core/management/base.py", line 242, in run_from_argv self.execute(*args, **options.__dict__) File "/home/markus/.venvs/django-master-py3/src/django/django/core/management/base.py", line 289, in execute output = self.handle(*args, **options) File "/home/markus/.venvs/django-master-py3/src/django/django/core/management/commands/migrate.py", line 52, in handle executor = MigrationExecutor(connection, self.migration_progress_callback) File "/home/markus/.venvs/django-master-py3/src/django/django/db/migrations/executor.py", line 14, in __init__ self.loader.load_disk() File "/home/markus/.venvs/django-master-py3/src/django/django/db/migrations/loader.py", line 77, in load_disk migration_module = import_module("%s.%s" % (module_name, migration_name)) File "/home/markus/.venvs/django-master-py3/lib/python3.3/importlib/__init__.py", line 90, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "<frozen importlib._bootstrap>", line 1586, in _gcd_import File "<frozen importlib._bootstrap>", line 1567, in _find_and_load File "<frozen importlib._bootstrap>", line 1534, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 586, in _check_name_wrapper File "<frozen importlib._bootstrap>", line 1024, in load_module File "<frozen importlib._bootstrap>", line 1005, in load_module File "<frozen importlib._bootstrap>", line 562, in module_for_loader_wrapper File "<frozen importlib._bootstrap>", line 870, in _load_module File "<frozen importlib._bootstrap>", line 313, in _call_with_frames_removed File "/home/markus/Coding/django-testing/example/something/migrations/0001_initial.py", line 6, in <module> class Migration(migrations.Migration): File "/home/markus/Coding/django-testing/example/something/migrations/0001_initial.py", line 20, in Migration fields = [('id', models.AutoField(serialize=False, auto_created=True, primary_key=True, verbose_name='ID'),), ('mymodel', models.ForeignKey(t_field='id', on_delete=django.db.models.deletion.set_on_delete, null=True, to='something.MyModel'),), ('value', models.IntegerField(default=50, bank=True, verbose_name='Value'),)], AttributeError: 'module' object has no attribute 'set_on_delete'
Migrating with Python 2.7.5:
Traceback (most recent call last): File "manage.py", line 10, in <module> execute_from_command_line(sys.argv) File "/home/markus/.venvs/django-master-py27/src/django/django/core/management/__init__.py", line 397, in execute_from_command_line utility.execute() File "/home/markus/.venvs/django-master-py27/src/django/django/core/management/__init__.py", line 390, in execute self.fetch_command(subcommand).run_from_argv(self.argv) File "/home/markus/.venvs/django-master-py27/src/django/django/core/management/base.py", line 242, in run_from_argv self.execute(*args, **options.__dict__) File "/home/markus/.venvs/django-master-py27/src/django/django/core/management/base.py", line 289, in execute output = self.handle(*args, **options) File "/home/markus/.venvs/django-master-py27/src/django/django/core/management/commands/migrate.py", line 52, in handle executor = MigrationExecutor(connection, self.migration_progress_callback) File "/home/markus/.venvs/django-master-py27/src/django/django/db/migrations/executor.py", line 14, in __init__ self.loader.load_disk() File "/home/markus/.venvs/django-master-py27/src/django/django/db/migrations/loader.py", line 77, in load_disk migration_module = import_module("%s.%s" % (module_name, migration_name)) File "/usr/lib64/python2.7/importlib/__init__.py", line 37, in import_module __import__(name) File "/home/markus/Coding/django-testing/example/something/migrations/0001_initial.py", line 6, in <module> class Migration(migrations.Migration): File "/home/markus/Coding/django-testing/example/something/migrations/0001_initial.py", line 18, in Migration fields = [(u'id', models.AutoField(verbose_name=u'ID', serialize=False, auto_created=True, primary_key=True),), ('mymodel', models.ForeignKey(to=u'something.MyModel', to_field=u'id', null=True, on_delete=django.db.models.deletion.set_on_delete),), ('value', models.IntegerField(default=50, verbose_name='Value', blank=True),)], AttributeError: 'module' object has no attribute 'set_on_delete'
Change History (6)
comment:1 by , 11 years ago
Triage Stage: | Unreviewed → Accepted |
---|
comment:2 by , 11 years ago
Has patch: | set |
---|
comment:3 by , 11 years ago
Yeah, your solution obviously works, but is more a workaround than a fix. That said, I'm actually not happy with this patch and would like to either change the ticket to cover closures in general and provide a proper patch or close this issue and open a new one covering the general problem.
comment:4 by , 11 years ago
Owner: | set to |
---|---|
Status: | new → assigned |
Updated the PR with a generic solution for closures.
comment:5 by , 11 years ago
Resolution: | → fixed |
---|---|
Status: | assigned → closed |
PR https://github.com/django/django/pull/1542.
This fixes the particular case of
SET_NULL
which should be a pretty common case.That said the underlying problem remains for
SET
which relies on a closure, the serialization system is not going to like closure in general. Maybe the value passed toSET
should be stored on the field itself so it can be recovered, just likeSET_DEFAULT
relies onfield.get_default()
.