django.db.utils.OperationalError中的./manage.py测试结果:没有这样的列:MyNewColumn

时间:2015-11-30 15:14:58

标签: python django testing migration

长话短说:我使用tests.py来覆盖我的django代码,我修改了很多代码和模型(18次迁移),一切都很好。

但是在上次更改和迁移(添加了一些布尔文件)后,我的测试开始在第8次迁移时崩溃

django.db.utils.OperationalError: no such column: tickets_ticket.ActionRequired

在网站上的Apache中,我可以使用新列,使用它添加模型,一切看起来都不错,但测试失败

有人可以告诉我,出了什么问题以及如何纠正它?

长篇故事:

Models.py:

def Ticket_generateUniqueID(related=''):
    retval=''
    sanitized=''
......
    # --- now find unique value
    while True:
            passNo += 1
            retval = generateID()
            try:
                    t = Ticket.objects.get(ticket_number=retval)
                    pass
            except ObjectDoesNotExist:
                    return retval
....
class Ticket(models.Model):
....
    ticket_number = models.CharField(max_length=100,default=Ticket_generateUniqueID,help_text=u"ID of ticket")
    ActionRequired = models.BooleanField(default=False,help_text=u"Action Required")
    def save(self):  # {{{
        if not self.id and not self.ticket_number: self.ticket_number=Ticket_generateUniqueID('OTH')
        retval=super(Ticket,self).save()
        return retval

和我的测试会话(应该从没有test_ *数据库开始)

$ ./manage.py test -v3
settings ...
Creating test database for alias 'default' (':memory:')...
Operations to perform:
  Synchronize unmigrated apps: django_extensions
  Apply all migrations: admin, tickets, contenttypes, auth, sessions
Synchronizing apps without migrations:
Running pre-migrate handlers for application admin
Running pre-migrate handlers for application auth
Running pre-migrate handlers for application contenttypes
Running pre-migrate handlers for application sessions
Running pre-migrate handlers for application django_extensions
Running pre-migrate handlers for application tickets
  Creating tables...
  Installing custom SQL...
  Installing indexes...
Loading 'initial_data' fixtures...
Checking '/home/gilhad/GIT/kompitech_test/src/kompitech_test' for fixtures...
No fixture 'initial_data' in '/home/gilhad/GIT/kompitech_test/src/kompitech_test'.
Installed 0 object(s) from 0 fixture(s)
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying sessions.0001_initial... OK
  Applying tickets.0001_initial... OK
  Applying tickets.0002_importedemail_is_new... OK
  Applying tickets.0003_auto_20151102_1642... OK
  Applying tickets.0004_auto_20151116_1633... OK
  Applying tickets.0005_auto_20151118_0756... OK
  Applying tickets.0006_emailpart_originalfilename... OK
  Applying tickets.0007_ticket_fv_ticket_id... OK
  Applying tickets.0008_auto_20151123_1430...Traceback (most recent call last):
  File "./manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/usr/lib/python2.7/dist-packages/django/core/management/__init__.py", line 385, in execute_from_command_line
    utility.execute()
  File "/usr/lib/python2.7/dist-packages/django/core/management/__init__.py", line 377, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/usr/lib/python2.7/dist-packages/django/core/management/commands/test.py", line 50, in run_from_argv
    super(Command, self).run_from_argv(argv)
  File "/usr/lib/python2.7/dist-packages/django/core/management/base.py", line 288, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "/usr/lib/python2.7/dist-packages/django/core/management/commands/test.py", line 71, in execute
    super(Command, self).execute(*args, **options)
  File "/usr/lib/python2.7/dist-packages/django/core/management/base.py", line 338, in execute
    output = self.handle(*args, **options)
  File "/usr/lib/python2.7/dist-packages/django/core/management/commands/test.py", line 88, in handle
    failures = test_runner.run_tests(test_labels)
  File "/usr/lib/python2.7/dist-packages/django/test/runner.py", line 147, in run_tests
    old_config = self.setup_databases()
  File "/usr/lib/python2.7/dist-packages/django/test/runner.py", line 109, in setup_databases
    return setup_databases(self.verbosity, self.interactive, **kwargs)
  File "/usr/lib/python2.7/dist-packages/django/test/runner.py", line 299, in setup_databases
    serialize=connection.settings_dict.get("TEST", {}).get("SERIALIZE", True),
  File "/usr/lib/python2.7/dist-packages/django/db/backends/creation.py", line 377, in create_test_db
    test_flush=True,
  File "/usr/lib/python2.7/dist-packages/django/core/management/__init__.py", line 115, in call_command
    return klass.execute(*args, **defaults)
  File "/usr/lib/python2.7/dist-packages/django/core/management/base.py", line 338, in execute
    output = self.handle(*args, **options)
  File "/usr/lib/python2.7/dist-packages/django/core/management/commands/migrate.py", line 161, in handle
    executor.migrate(targets, plan, fake=options.get("fake", False))
  File "/usr/lib/python2.7/dist-packages/django/db/migrations/executor.py", line 68, in migrate
    self.apply_migration(migration, fake=fake)
  File "/usr/lib/python2.7/dist-packages/django/db/migrations/executor.py", line 102, in apply_migration
    migration.apply(project_state, schema_editor)
  File "/usr/lib/python2.7/dist-packages/django/db/migrations/migration.py", line 108, in apply
    operation.database_forwards(self.app_label, schema_editor, project_state, new_state)
  File "/usr/lib/python2.7/dist-packages/django/db/migrations/operations/fields.py", line 139, in database_forwards
    schema_editor.alter_field(from_model, from_field, to_field)
  File "/usr/lib/python2.7/dist-packages/django/db/backends/schema.py", line 457, in alter_field
    self._alter_field(model, old_field, new_field, old_type, new_type, old_db_params, new_db_params, strict)
  File "/usr/lib/python2.7/dist-packages/django/db/backends/sqlite3/schema.py", line 202, in _alter_field
    self._remake_table(model, alter_fields=[(old_field, new_field)])
  File "/usr/lib/python2.7/dist-packages/django/db/backends/sqlite3/schema.py", line 139, in _remake_table
    self.create_model(temp_model)
  File "/usr/lib/python2.7/dist-packages/django/db/backends/schema.py", line 213, in create_model
    definition, extra_params = self.column_sql(model, field)
  File "/usr/lib/python2.7/dist-packages/django/db/backends/schema.py", line 125, in column_sql
    default_value = self.effective_default(field)
  File "/usr/lib/python2.7/dist-packages/django/db/backends/schema.py", line 175, in effective_default
    default = field.get_default()
  File "/usr/lib/python2.7/dist-packages/django/db/models/fields/__init__.py", line 719, in get_default
    return self.default()
  File "/home/gilhad/GIT/kompitech_test/src/kompitech_test/tickets/models.py", line 56, in Ticket_generateUniqueID
    t = Ticket.objects.get(ticket_number=retval)
  File "/usr/lib/python2.7/dist-packages/django/db/models/manager.py", line 92, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/usr/lib/python2.7/dist-packages/django/db/models/query.py", line 351, in get
    num = len(clone)
  File "/usr/lib/python2.7/dist-packages/django/db/models/query.py", line 122, in __len__
    self._fetch_all()
  File "/usr/lib/python2.7/dist-packages/django/db/models/query.py", line 966, in _fetch_all
    self._result_cache = list(self.iterator())
  File "/usr/lib/python2.7/dist-packages/django/db/models/query.py", line 265, in iterator
    for row in compiler.results_iter():
  File "/usr/lib/python2.7/dist-packages/django/db/models/sql/compiler.py", line 700, in results_iter
    for rows in self.execute_sql(MULTI):
  File "/usr/lib/python2.7/dist-packages/django/db/models/sql/compiler.py", line 786, in execute_sql
    cursor.execute(sql, params)
  File "/usr/lib/python2.7/dist-packages/django/db/backends/utils.py", line 65, in execute
    return self.cursor.execute(sql, params)
  File "/usr/lib/python2.7/dist-packages/django/db/utils.py", line 94, in __exit__
    six.reraise(dj_exc_type, dj_exc_value, traceback)
  File "/usr/lib/python2.7/dist-packages/django/db/backends/utils.py", line 65, in execute
    return self.cursor.execute(sql, params)
  File "/usr/lib/python2.7/dist-packages/django/db/backends/sqlite3/base.py", line 485, in execute
    return Database.Cursor.execute(self, query, params)
django.db.utils.OperationalError: no such column: tickets_ticket.ActionRequired

请注意,它几乎不是最后一次迁移,而且每次测试之前都会进行测试

$ ls -1 tickets/migrations/*py
tickets/migrations/0001_initial.py
tickets/migrations/0002_importedemail_is_new.py
tickets/migrations/0003_auto_20151102_1642.py
tickets/migrations/0004_auto_20151116_1633.py
tickets/migrations/0005_auto_20151118_0756.py
tickets/migrations/0006_emailpart_originalfilename.py
tickets/migrations/0007_ticket_fv_ticket_id.py
tickets/migrations/0008_auto_20151123_1430.py
tickets/migrations/0009_auto_20151123_1718.py
tickets/migrations/0010_auto_20151123_1928.py
tickets/migrations/0011_auto_20151124_0938.py
tickets/migrations/0012_auto_20151125_1351.py
tickets/migrations/0013_auto_20151125_1406.py
tickets/migrations/0014_configemailcompany.py
tickets/migrations/0015_auto_20151126_1435.py
tickets/migrations/0016_configemailcompany_we.py
tickets/migrations/0017_auto_20151126_1730.py
tickets/migrations/0018_auto_20151127_1103.py
tickets/migrations/0019_auto_20151130_0934.py
tickets/migrations/__init__.py

失败的迁移:

migrations.AlterField(
    model_name='ticket',
    name='by_user',
    field=models.ForeignKey(related_name='changed_records_of_ticket', blank=True, to=settings.AUTH_USER_MODEL, help_text='Last modification was by this user (autofilled)', null=True, db_index=False),
    preserve_default=True,
    ),
migrations.AlterField(
    model_name='ticket',
    name='ticket_number',
    field=models.CharField(default=tickets.models.Ticket_generateUniqueID, help_text='ID of ticket', max_length=100),
    preserve_default=True,
   ),

(以及其他模型中许多其他by_user更改)

2 个答案:

答案 0 :(得分:4)

问题是用于获取默认值的Ticket_generateUniqueID方法是尝试获取尚未创建迁移的列。

try:
    t = Ticket.objects.get(ticket_number=retval)
    pass
except ObjectDoesNotExist:
    return retval

在这种情况下,我认为您可以通过更改方法来使用exists()而不是get()来避免此问题。

if Ticket.objects.filter(ticket_number=retval).exists():
    pass
else:
    return retval

如果无法重写默认方法,则修复起来会比较棘手。我相信您必须在导致错误的迁移之前添加数据迁移,并在那里设置字段值。在数据迁移中,您可以使用Ticket = apps.get_model('myapp', 'Ticket')。然后,您就可以毫无错误地运行Ticket.objects.get()

答案 1 :(得分:0)

只有一个更新:当我删除所有迁移并将它们重新创建为一个简单时,我的测试开始失败:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Routes.MapHttpRoute(
            name: "ActionRoute",
            routeTemplate: "api/{controller}/{action}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}

因为我的测试创建(并没有保存)在加载夹具之前的票证对象,所以我在while循环之前添加了这个健全性测试:

django.db.utils.OperationalError: no such table: tickets_ticket