2016-09-07 2 views
3

В Django 1.9, используя SQLite в качестве базы данных, я получаю сообщение об ошибке при попытке применить миграции после модификации модели для использования наследования с несколькими таблицами вместо OneToOneField которые ранее использовались.Django + SQLite + ForeignKey ('self') = Failed Migration

В частности, проблема связана с включением модели ForeignKey('self') в модель.

models.py

Вот приложение, из которого первоначальных миграции успешно выполнены, и применяются:

from django.db import models 
from django.contrib.auth.models import User 


class Customer(models.Model): 
    account = models.OneToOneField(User) 
    parent = models.ForeignKey('self', null=True) 

models.py (модифицированный)

Приложения затем модифицируются, чтобы наследовать от модели пользователя, а не ссылки на него:

from django.db import models 
from django.contrib.auth.models import User 

class Customer(User): 
    parent = models.ForeignKey('self', null=True) 

В этой точке T A ./manage.py makemigrations <app> успешно, но затем приклеивается миграция терпит неудачу с:

Ошибки

Traceback (most recent call last): 
    File "./manage.py", line 10, in <module> 
    execute_from_command_line(sys.argv) 
    File "/home/piranha/.virtualenvs/Python_3.5-Django_1.9/lib/python3.5/site-packages/django/core/management/__init__.py", line 353, in execute_from_command_line 
    utility.execute() 
    File "/home/piranha/.virtualenvs/Python_3.5-Django_1.9/lib/python3.5/site-packages/django/core/management/__init__.py", line 345, in execute 
    self.fetch_command(subcommand).run_from_argv(self.argv) 
    File "/home/piranha/.virtualenvs/Python_3.5-Django_1.9/lib/python3.5/site-packages/django/core/management/base.py", line 348, in run_from_argv 
    self.execute(*args, **cmd_options) 
    File "/home/piranha/.virtualenvs/Python_3.5-Django_1.9/lib/python3.5/site-packages/django/core/management/base.py", line 399, in execute 
    output = self.handle(*args, **options) 
    File "/home/piranha/.virtualenvs/Python_3.5-Django_1.9/lib/python3.5/site-packages/django/core/management/commands/migrate.py", line 200, in handle 
    executor.migrate(targets, plan, fake=fake, fake_initial=fake_initial) 
    File "/home/piranha/.virtualenvs/Python_3.5-Django_1.9/lib/python3.5/site-packages/django/db/migrations/executor.py", line 92, in migrate 
    self._migrate_all_forwards(plan, full_plan, fake=fake, fake_initial=fake_initial) 
    File "/home/piranha/.virtualenvs/Python_3.5-Django_1.9/lib/python3.5/site-packages/django/db/migrations/executor.py", line 121, in _migrate_all_forwards 
    state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_initial) 
    File "/home/piranha/.virtualenvs/Python_3.5-Django_1.9/lib/python3.5/site-packages/django/db/migrations/executor.py", line 198, in apply_migration 
    state = migration.apply(state, schema_editor) 
    File "/home/piranha/.virtualenvs/Python_3.5-Django_1.9/lib/python3.5/site-packages/django/db/migrations/migration.py", line 123, in apply 
    operation.database_forwards(self.app_label, schema_editor, old_state, project_state) 
    File "/home/piranha/.virtualenvs/Python_3.5-Django_1.9/lib/python3.5/site-packages/django/db/migrations/operations/fields.py", line 62, in database_forwards 
    field, 
    File "/home/piranha/.virtualenvs/Python_3.5-Django_1.9/lib/python3.5/site-packages/django/db/backends/sqlite3/schema.py", line 221, in add_field 
    self._remake_table(model, create_fields=[field]) 
    File "/home/piranha/.virtualenvs/Python_3.5-Django_1.9/lib/python3.5/site-packages/django/db/backends/sqlite3/schema.py", line 181, in _remake_table 
    self.create_model(temp_model) 
    File "/home/piranha/.virtualenvs/Python_3.5-Django_1.9/lib/python3.5/site-packages/django/db/backends/base/schema.py", line 250, in create_model 
    to_column = field.remote_field.model._meta.get_field(field.remote_field.field_name).column 
    File "/home/piranha/.virtualenvs/Python_3.5-Django_1.9/lib/python3.5/site-packages/django/db/models/options.py", line 582, in get_field 
    raise FieldDoesNotExist('%s has no field named %r' % (self.object_name, field_name)) 
django.core.exceptions.FieldDoesNotExist: Customer has no field named 'id' 

Опять же, проблема, кажется, происходит только при использовании SQLite и в том числе автореферентного ForeignKey. Я думаю, что это происходит потому, что SQLite не может использовать столбцы ALTER, в результате чего Django восстанавливает таблицу, но саморегуляция ForeignKey заставляет перестроить искать столбец «id», который больше не существует в новой модели.

Я попытался вручную настроить миграционные операции каждый, и даже добавить migrations.RunPython с apps.get_model(), чтобы использовать историческую версию модели. Ничто не работает.

Как я могу настроить следующую миграцию, чтобы избежать ошибки:

миграции

# -*- coding: utf-8 -*- 
# Generated by Django 1.9.2 on 2016-09-07 01:16 
from __future__ import unicode_literals 

from django.conf import settings 
import django.contrib.auth.models 
from django.db import migrations, models 
import django.db.models.deletion 


class Migration(migrations.Migration): 

    dependencies = [ 
     migrations.swappable_dependency(settings.AUTH_USER_MODEL), 
     ('base', '0001_initial'), 
    ] 

    operations = [ 
     migrations.AlterModelOptions(
      name='customer', 
      options={'verbose_name': 'user', 'verbose_name_plural': 'users'}, 
     ), 
     migrations.AlterModelManagers(
      name='customer', 
      managers=[ 
       ('objects', django.contrib.auth.models.UserManager()), 
      ], 
     ), 
     migrations.RemoveField(
      model_name='customer', 
      name='account', 
     ), 
     migrations.RemoveField(
      model_name='customer', 
      name='id', 
     ), 
     migrations.AddField(
      model_name='customer', 
      name='user_ptr', 
      field=models.OneToOneField(auto_created=True, default=None, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to=settings.AUTH_USER_MODEL), 
      preserve_default=False, 
     ), 
    ] 

И, да, я знаю, что в конечном счете нужно разбить миграцию в несколько этапов и сделать данные миграция, чтобы добавить что-то полезное в новое поле user_ptr.

+0

Есть ли у вас какие-либо ранее существовавшие миграции? Если это так, я бы предложил удалить все ваши миграции и снова запустить их. – Written

+0

Я воспроизвел эту ошибку, используя только код выше. Единственные две миграции - это начальная (сделанная из первого кодового блока), а вторая - ошибка. – PiranhaP

+0

Правильно, я бы рекомендовал удалить оба файла и перезапустить свои миграции, посмотреть, устраняет ли это проблему. – Written

ответ

0

Хорошо, что мне потребовалось некоторое время, чтобы работать: но в принципе, я не думаю, что вы можете сделать это:

class Customer(User): 
    parent = models.ForeignKey('self', null=True) 

Вместо этого, он должен быть чем-то больше похоже (непроверенных :)

class Customer(User): 
    parent = models.ForeignKey('admin.User', null=True) 

Если вы хотите, чтобы убедиться, что целостность данных на самом деле клиент, вы могли бы поставить предварительно проверить в экономии (или что-то, если вы используете копи-конвейер какой-то)

Если вы включить миграцию данных чтобы сохранить это значение, возможно, используя временное значение для его хранения (или сбрасывать и повторно вставлять объекты).