Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django 1.7 Migration error on foreignkey with default value

I have a problem concerning testing my app including migrations on ForeignKey modelfields having a default value (see example below, field mode in model RuleSet).

I don't know if that's a bug in Django 1.7 testing migrations or if I'm doing something wrong

#models.py:

RULE_SET_MODE__ACTIVE = "Active"

def default_mode():
    return RuleSetMode.objects.get(name=RULE_SET_MODE__ACTIVE)

class RuleSetMode(models.Model):
    name = models.CharField(max_length=30)
    description = models.CharField(max_length=255)

class RuleSet(models.Model):
    name = models.CharField(max_length=30, unique=True)
    description = models.CharField(max_length=255)
    mode = models.ForeignKey(RuleSetMode, default=default_mode)

I tried following migration steps so far:

  1. created an initial migration with default value (function)
  2. created an initial migration without default value and created a second migration changing the field by setting the default value

None of them worked for me. So you can see that the problem is not related to migrating the field itself. It's just related to the fact that migrations exists for the app.

(Overriding the save method would be a solution or disabling migrations during tests using this solution: Disable migrations when running unit tests in Django 1.7 , but I would prefer setting the default attribute)

#migrations file (altering the existing field):

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

from django.db import models, migrations
import myapp.models


class Migration(migrations.Migration):

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

    operations = [
        migrations.AlterField(
            model_name='ruleset',
            name='mode',
            field=models.ForeignKey(default=myapp.models.default_mode, to='myapp.RuleSetMode'),
        ),
    ]

The output executing: python manage.py test myapp:

Creating test database for alias 'default'...
Traceback (most recent call last):
File "manage.py", line 16, in <module>
execute_from_command_line(sys.argv)
File "/home/cgossy/venvs/django-1.7/local/lib/python2.7/site-packages/Django-1.7-py2.7.egg/django/core/management/__init__.py", line 385, in execute_from_command_line
utility.execute()
File "/home/cgossy/venvs/django-1.7/local/lib/python2.7/site-packages/Django-1.7-py2.7.egg/django/core/management/__init__.py", line 377, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/home/cgossy/venvs/django-1.7/local/lib/python2.7/site-packages/Django-1.7-py2.7.egg/django/core/management/commands/test.py", line 50, in run_from_argv
super(Command, self).run_from_argv(argv)
File "/home/cgossy/venvs/django-1.7/local/lib/python2.7/site-packages/Django-1.7-py2.7.egg/django/core/management/base.py", line 288, in run_from_argv
self.execute(*args, **options.__dict__)
File "/home/cgossy/venvs/django-1.7/local/lib/python2.7/site-packages/Django-1.7-py2.7.egg/django/core/management/commands/test.py", line 71, in execute
super(Command, self).execute(*args, **options)
File "/home/cgossy/venvs/django-1.7/local/lib/python2.7/site-packages/Django-1.7-py2.7.egg/django/core/management/base.py", line 338, in execute
output = self.handle(*args, **options)
File "/home/cgossy/venvs/django-1.7/local/lib/python2.7/site-packages/Django-1.7-py2.7.egg/django/core/management/commands/test.py", line 88, in handle
failures = test_runner.run_tests(test_labels)
File "/home/cgossy/venvs/django-1.7/local/lib/python2.7/site-packages/Django-1.7-py2.7.egg/django/test/runner.py", line 147, in run_tests
old_config = self.setup_databases()
File "/home/cgossy/venvs/django-1.7/local/lib/python2.7/site-packages/Django-1.7-py2.7.egg/django/test/runner.py", line 109, in setup_databases
return setup_databases(self.verbosity, self.interactive, **kwargs)
File "/home/cgossy/venvs/django-1.7/local/lib/python2.7/site-packages/Django-1.7-py2.7.egg/django/test/runner.py", line 299, in setup_databases
serialize=connection.settings_dict.get("TEST_SERIALIZE", True),
File "/home/cgossy/venvs/django-1.7/local/lib/python2.7/site-packages/Django-1.7-py2.7.egg/django/db/backends/creation.py", line 374, in create_test_db
test_flush=True,
File "/home/cgossy/venvs/django-1.7/local/lib/python2.7/site-packages/Django-1.7-py2.7.egg/django/core/management/__init__.py", line 115, in call_command
return klass.execute(*args, **defaults)
File "/home/cgossy/venvs/django-1.7/local/lib/python2.7/site-packages/Django-1.7-py2.7.egg/django/core/management/base.py", line 338, in execute
output = self.handle(*args, **options)
File "/home/cgossy/venvs/django-1.7/local/lib/python2.7/site-packages/Django-1.7-py2.7.egg/django/core/management/commands/migrate.py", line 160, in handle
executor.migrate(targets, plan, fake=options.get("fake", False))
File "/home/cgossy/venvs/django-1.7/local/lib/python2.7/site-packages/Django-1.7-py2.7.egg/django/db/migrations/executor.py", line 63, in migrate
self.apply_migration(migration, fake=fake)
File "/home/cgossy/venvs/django-1.7/local/lib/python2.7/site-packages/Django-1.7-py2.7.egg/django/db/migrations/executor.py", line 97, in apply_migration
migration.apply(project_state, schema_editor)
File "/home/cgossy/venvs/django-1.7/local/lib/python2.7/site-packages/Django-1.7-py2.7.egg/django/db/migrations/migration.py", line 107, in apply
operation.database_forwards(self.app_label, schema_editor, project_state, new_state)
File "/home/cgossy/venvs/django-1.7/local/lib/python2.7/site-packages/Django-1.7-py2.7.egg/django/db/migrations/operations/fields.py", line 131, in database_forwards
schema_editor.alter_field(from_model, from_field, to_field)
File "/home/cgossy/venvs/django-1.7/local/lib/python2.7/site-packages/Django-1.7-py2.7.egg/django/db/backends/schema.py", line 509, in alter_field
self._alter_field(model, old_field, new_field, old_type, new_type, old_db_params, new_db_params, strict)
File "/home/cgossy/venvs/django-1.7/local/lib/python2.7/site-packages/Django-1.7-py2.7.egg/django/db/backends/sqlite3/schema.py", line 183, in _alter_field
self._remake_table(model, alter_fields=[(old_field, new_field)])
File "/home/cgossy/venvs/django-1.7/local/lib/python2.7/site-packages/Django-1.7-py2.7.egg/django/db/backends/sqlite3/schema.py", line 121, in _remake_table
self.create_model(temp_model)
File "/home/cgossy/venvs/django-1.7/local/lib/python2.7/site-packages/Django-1.7-py2.7.egg/django/db/backends/schema.py", line 208, in create_model
definition, extra_params = self.column_sql(model, field)
File "/home/cgossy/venvs/django-1.7/local/lib/python2.7/site-packages/Django-1.7-py2.7.egg/django/db/backends/schema.py", line 120, in column_sql
default_value = self.effective_default(field)
File "/home/cgossy/venvs/django-1.7/local/lib/python2.7/site-packages/Django-1.7-py2.7.egg/django/db/backends/schema.py", line 170, in effective_default
default = field.get_default()
File "/home/cgossy/venvs/django-1.7/local/lib/python2.7/site-packages/Django-1.7-py2.7.egg/django/db/models/fields/related.py", line 1711, in get_default
field_default = super(ForeignKey, self).get_default()
File "/home/cgossy/venvs/django-1.7/local/lib/python2.7/site-packages/Django-1.7-py2.7.egg/django/db/models/fields/__init__.py", line 719, in get_default
return self.default()
File "/usr/local/lib/python2.7/dev-packages/kiola/kiola_alfred/models.py", line 33, in default_mode
return RuleSetMode.objects.get(name=RULE_SET_MODE__ACTIVE)
File "/home/cgossy/venvs/django-1.7/local/lib/python2.7/site-packages/Django-1.7-py2.7.egg/django/db/models/manager.py", line 92, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/cgossy/venvs/django-1.7/local/lib/python2.7/site-packages/Django-1.7-py2.7.egg/django/db/models/query.py", line 357, in get
self.model._meta.object_name)
myapp.models.DoesNotExist: RuleSetMode matching query does not exist.

Any ideas are welcome

like image 383
Cosy Avatar asked Sep 25 '14 08:09

Cosy


People also ask

Is Django migration necessary?

Migrations are not required. They can be useful for creating and tracking database changes via code, but Django applications will run properly without them.

What does Makemigrations do in Django?

makemigrations is responsible for packaging up your model changes into individual migration files - analogous to commits - and migrate is responsible for applying those to your database.

What is foreign key relationship in Django?

Introduction to Django Foreign Key. A foreign key is a process through which the fields of one table can be used in another table flexibly. So, two different tables can be easily linked by means of the foreign key. This linking of the two tables can be easily achieved by means of foreign key processes.


1 Answers

I found a solution for my problem.

The problem is that the data base is - of course- empty while migrations are applied. Since

migrations.AlterField(
        model_name='ruleset',
        name='mode',
        field=models.ForeignKey(default=myapp.models.default_mode, to='myapp.RuleSetMode'),
    ),

uses

models.ForeignKey(default=myapp.models.default_mode, to='myapp.RuleSetMode')

the function used for setting the default value is executed. But there is no value in the Database.

Now I added a data migration between initial migration and the migration which adds the default value.

This looks like that:

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

from django.db import models, migrations


def set_default_values(apps, schema_editor):
    # We can't import the Person model directly as it may be a newer
    # version than this migration expects. We use the historical version.
    import myapp.const as const
    RuleSetMode = apps.get_model("myapp", "RuleSetMode")
    RuleSetMode.objects.get_or_create(name=const.RULE_SET_MODE__ACTIVE)


class Migration(migrations.Migration):

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

    operations = [
        migrations.RunPython(set_default_values),
    ]

and in the migration which adds the default value gets the dependency list is changed to:

dependencies = [
    ('myapp', '0002_auto_20140925_1458'),
]
like image 146
Cosy Avatar answered Sep 30 '22 18:09

Cosy