6

I'd like to seed a superuser record in a data migration for a django 1.7 project. I'm using the django-custom-user app. My migration looks like this:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations

def load_data(apps, schema_editor):
    EmailUser = apps.get_model('custom_user', 'EmailUser')
    root = EmailUser.objects.create_superuser(email='admin@somesite.com', password='supersecure')


class Migration(migrations.Migration):
    dependencies = [
        ('accounts', '0001_initial'),
    ]

    operations = [
        migrations.RunPython(load_data)
    ]

When running ./manage.py migrate I get the following error:

Running migrations:
  Applying accounts.0002_initial_data...Traceback (most recent call last):
  File "./manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/usr/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 385, in execute_from_command_line
    utility.execute()
  File "/usr/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 377, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/usr/local/lib/python2.7/site-packages/django/core/management/base.py", line 288, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "/usr/local/lib/python2.7/site-packages/django/core/management/base.py", line 338, in execute
    output = self.handle(*args, **options)
  File "/usr/local/lib/python2.7/site-packages/django/core/management/commands/migrate.py", line 161, in handle
    executor.migrate(targets, plan, fake=options.get("fake", False))
  File "/usr/local/lib/python2.7/site-packages/django/db/migrations/executor.py", line 68, in migrate
    self.apply_migration(migration, fake=fake)
  File "/usr/local/lib/python2.7/site-packages/django/db/migrations/executor.py", line 102, in apply_migration
    migration.apply(project_state, schema_editor)
  File "/usr/local/lib/python2.7/site-packages/django/db/migrations/migration.py", line 105, in apply
    operation.database_forwards(self.app_label, schema_editor, project_state, new_state)
  File "/usr/local/lib/python2.7/site-packages/django/db/migrations/operations/special.py", line 117, in database_forwards
    self.code(from_state.render(), schema_editor)
  File "/Users/spoolphiz/work/somesite/accounts/migrations/0002_initial_data.py", line 14, in load_data
    root = EmailUser.objects.create_superuser(email='admin@somesite.com', password='f00b@r')
AttributeError: 'Manager' object has no attribute 'create_superuser'

I see that EmailUserManager does have a create_superuser method. Am I incorrectly invoking the manager's function?

Edit:

I see the same issue here. Is duplicating all code really the best solution? Seems like at that point I'd be better off using RunSQL and manually performing the inserts.

Community
  • 1
  • 1
novon
  • 973
  • 3
  • 15
  • 30

2 Answers2

5

I'm seeing the same issue as @cpury in 1.8.4. I set use_in_migrations=True in my manager but unexpectedly the custom manager method is not available in a data migration using Model.objects.my_custom_method(), giving the same error above. The workaround I did was to import the manager and instantiate it. The problem then was that self.model is None since it is unattached to the model. So then I did the following and it seems to work, although I don't understand why the use_in_migrations flag doesn't work as I expected.

from appname.managers import MyManager
def add_data(apps, schema_editor):
    mgr = MyManager()
    mgr.model = apps.get_model('appname', 'Model')
    mgr.my_method_that_adds_data()

Edit: It looks like the AlterModelManagers operation which sets the custom manager for the model had not been created yet and it showed up in a later migration. I might have forgotten to run 'makemigrations' before 'makemigrations --empty'. I moved this operation before the RunPython call to add_data() but still get the AttributeError.

ybendana
  • 1,613
  • 1
  • 16
  • 17
  • Hit same issue on Django 1.8.7, ybendana's workaround was the only approached that worked, despite setting `use_in_migrations=True` ([see docs](https://docs.djangoproject.com/en/1.8/topics/migrations/#using-managers-in-migrations)) in a previous migration. – lightstrike Dec 02 '15 at 17:01
  • `use_in_migrations=True` probably doesn't work because of this: https://github.com/django/django/pull/7110 – DiegoG Oct 09 '19 at 04:30
0

Unfortunately managers weren't serialized before Django 1.8 hence the AttributeError you're getting here.

I suggest you upgrade to Django==1.8b1 and run makemigration to serialize your custom user manager. Else you'll need to use your vanilla manager's create method to mimic what UserManager.create_superuser does.

Simon Charette
  • 5,009
  • 1
  • 25
  • 33
  • I'm having a similar problem using Django 1.8.2. It seems to me that only the fields of a model are serialized in the migrations, no class variables or methods. So even when calling makemigrations, the created migration does not include any data beyond the fields, and I can't call any of my methods. – cpury Jul 12 '15 at 03:23