Opened 9 years ago

Closed 9 years ago

Last modified 9 years ago

#25332 closed Bug (worksforme)

migrate fails for CharField if max_length is omitted

Reported by: Karolis Ryselis Owned by: nobody
Component: Migrations Version: 1.7
Severity: Normal Keywords: max_length CharField migrate
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

When adding a CharField to model and leaving out max_length undefined Django migration is created but fails when is run.

Consider this model:

class Order(Model):
    foo = models.DateField(verbose_name=_("Foo"))

We change it to this:

class Order(Model):
    foo = models.DateField(verbose_name=_("Foo"))
    payment_terms = models.CharField(verbose_name=_("Payment terms"), blank=True)

note that I omit max_length parameter. I run makemigrations for my app, the migration is created with the following operation:

        migrations.AddField(
            model_name='order',
            name='payment_terms',
            field=models.CharField(verbose_name='Payment terms', blank=True),
            preserve_default=True,
        )

When I run the migration, it spits the following error:

 File "/usr/lib/python3.4/runpy.py", line 182, in run_module
    return _run_module_code(code, init_globals, run_name, mod_spec)
  File "/usr/lib/python3.4/runpy.py", line 96, in _run_module_code
    mod_name, mod_spec, pkg_name, script_name)
  File "/usr/lib/python3.4/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/home/ryselis/PycharmProjects/ez_demo/manage.py", line 14, in <module>
    execute_from_command_line(sys.argv)
  File "/usr/local/lib/python3.4/dist-packages/django/core/management/__init__.py", line 385, in execute_from_command_line
    utility.execute()
  File "/usr/local/lib/python3.4/dist-packages/django/core/management/__init__.py", line 377, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/usr/local/lib/python3.4/dist-packages/django/core/management/base.py", line 288, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "/usr/local/lib/python3.4/dist-packages/django/core/management/base.py", line 338, in execute
    output = self.handle(*args, **options)
  File "/usr/local/lib/python3.4/dist-packages/django/core/management/commands/migrate.py", line 161, in handle
    executor.migrate(targets, plan, fake=options.get("fake", False))
  File "/usr/local/lib/python3.4/dist-packages/django/db/migrations/executor.py", line 68, in migrate
    self.apply_migration(migration, fake=fake)
  File "/usr/local/lib/python3.4/dist-packages/django/db/migrations/executor.py", line 102, in apply_migration
    migration.apply(project_state, schema_editor)
  File "/usr/local/lib/python3.4/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/local/lib/python3.4/dist-packages/django/db/migrations/operations/fields.py", line 37, in database_forwards
    field,
  File "/usr/local/lib/python3.4/dist-packages/mysql/connector/django/schema.py", line 49, in add_field
    super(DatabaseSchemaEditor, self).add_field(model, field)
  File "/usr/local/lib/python3.4/dist-packages/django/db/backends/schema.py", line 388, in add_field
    self.execute(sql, params)
  File "/usr/local/lib/python3.4/dist-packages/django/db/backends/schema.py", line 111, in execute
    cursor.execute(sql, params)
  File "/usr/local/lib/python3.4/dist-packages/django/db/backends/utils.py", line 81, in execute
    return super(CursorDebugWrapper, self).execute(sql, params)
  File "/usr/local/lib/python3.4/dist-packages/django/db/backends/utils.py", line 65, in execute
    return self.cursor.execute(sql, params)
  File "/usr/local/lib/python3.4/dist-packages/mysql/connector/django/base.py", line 133, in execute
    return self._execute_wrapper(self.cursor.execute, query, args)
  File "/usr/local/lib/python3.4/dist-packages/mysql/connector/django/base.py", line 116, in _execute_wrapper
    utils.ProgrammingError(err.msg), sys.exc_info()[2])
  File "/usr/local/lib/python3.4/dist-packages/django/utils/six.py", line 658, in reraise
    raise value.with_traceback(tb)
  File "/usr/local/lib/python3.4/dist-packages/mysql/connector/django/base.py", line 113, in _execute_wrapper
    return method(query, args)
  File "/usr/local/lib/python3.4/dist-packages/mysql/connector/cursor.py", line 507, in execute
    self._handle_result(self._connection.cmd_query(stmt))
  File "/usr/local/lib/python3.4/dist-packages/mysql/connector/connection.py", line 720, in cmd_query
    result = self._handle_result(self._send_cmd(ServerCmd.QUERY, query))
  File "/usr/local/lib/python3.4/dist-packages/mysql/connector/connection.py", line 638, in _handle_result
    raise errors.get_exception(packet)
django.db.utils.ProgrammingError: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'None) DEFAULT '' NOT NULL' at line 1

The SQL generated is

ALTER TABLE `myapp_order` ADD COLUMN `payment_terms` varchar(None) DEFAULT '' NOT NULL

The docs say that "The max_length is enforced at the database level and in Django’s validation."

I suppose this is not the correct behaviour. It used to generate a reasonable error messsage in earlier Django versions.

Change History (6)

comment:1 by Tim Graham, 9 years ago

Resolution: worksforme
Status: newclosed

I couldn't reproduce this.

$ python manage.py makemigrations
SystemCheckError: System check identified some issues:

ERRORS:
app.Order.payment_terms: (fields.E120) CharFields must define a 'max_length' attribute.

comment:2 by Karolis Ryselis, 9 years ago

I got the buggy behaviour on Django 1.7.10. Are you using the same version?

comment:3 by Karolis Ryselis, 9 years ago

This is my output for the same command:

$ python3 manage.py makemigrations myapp
Migrations for 'myapp':
  0039_auto_20150901_1502.py:
    - Add field payment_terms to order

comment:4 by Tim Graham, 9 years ago

Yes, I tested with the 1.7 branch. Here's the relevant code. Could you try to debug why it's not being called in your case?

comment:5 by Karolis Ryselis, 9 years ago

I have put a print on top of the method you have shown me. It is called for some fields, but not the others. It looks like it works for all Django built-in fields (those in contenttypes, auth), also other python libs that are built on top of Django, but for my project there are fields for one app only. It might be either problem with my project or some configuration. I have searched through code and found out that the checks are registered to the registry and then called. Could you point me to the code that registers this check?

comment:6 by Tim Graham, 9 years ago

Here you go -- model.check() then calls model._check_fields().

Note: See TracTickets for help on using tickets.
Back to Top