Opened 4 years ago

Closed 4 years ago

#23678 closed Bug (worksforme)

Database default not removed if default=None

Reported by: Tim Graham Owned by: nobody
Component: Migrations Version: 1.7
Severity: Release blocker Keywords:
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

If you have a model field like models.CharField(max_length=255, blank=True, null=True, default=None), you will end up something like varchar(255) DEFAULT NULL with MySQL. The DEFAULT NULL should be dropped but isn't due to the field.default is not None check here: https://github.com/django/django/blob/8d6e1afe0be0570253a508f43e2ef89ae640984e/django/db/backends/schema.py#L382

Change History (3)

comment:1 Changed 4 years ago by Paul Dejean

Not exactly accurate:

  • Every varchar column will have DEFAULT NULL if it's created on the inital migration, regardless of the value of the "default" keyword argument.
  • Every varchar column created as part of a non initial migration will have DEFAULT NULL if the "default" keyword argument is equal to None.
  • A varchar column that has its attributes changed that is DEFAULT NULL in the database will revert from DEFAULT NULL to no default if the "default" keyword argument is not None.
  • A varchar column that has its attributes changed that is DEFAULT NULL in the database will remain DEFAULT NULL if the "default" keyword argument is None.
  • A varchar column that has no default in the database will continue to have no default regardless of its "default" keyword argument. Meaning it will not at any point go back to DEFAULT NULL.

comment:2 Changed 4 years ago by Loic Bistuer

@paulcdejean how do you get those results? I just tried with the sqlmigrate command on initial migration on MySQL and my models.CharField(max_length=42, null=True) doesn't show a DEFAULT.

comment:3 in reply to:  2 Changed 4 years ago by Carl Meyer

Resolution: worksforme
Status: newclosed

Replying to loic:

@paulcdejean how do you get those results? I just tried with the sqlmigrate command on initial migration on MySQL and my models.CharField(max_length=42, null=True) doesn't show a DEFAULT.

You can see the difference as described if you actually run the migration and then check show create table tablename in MySQL.

However, I am not convinced that this reflects a bug in Django, as opposed to just a slightly odd behavior of show create table in MySQL. (I am not very familiar with MySQL, so I could well be missing something).

For one thing, this difference doesn't show up in describe tablename: all nullable fields with no other default show NULL in the "default" column, regardless of whether they show DEFAULT NULL in the show create table tablename output or not.

Secondly, if I add a column directly in MySQL (no involvement from Django) using this exact syntax: ALTER TABLE 'testapp_thing' ADD COLUMN 'direct' varchar(100); (note that I did not specify DEFAULT NULL, or any other default), this is what show create table testapp_thing gives for that column: 'direct' varchar(100) DEFAULT NULL,. In other words, MySQL seems to be adding that DEFAULT NULL itself, even if it wasn't in the ALTER TABLE.

And lastly, I am not convinced that any of this matters anyway. The nullable columns that do and don't show DEFAULT NULL in the show create table tablename output seem to behave identically - they all in practice still use NULL as their default value (consistent with the fact that they all show NULL in the "default" column of their describe output).

My conclusion: NULL is the "default default" for any nullable column without another explicit default value. There is no issue in Django here, just some strange (but harmless) behavior from MySQL.

Closing; please reopen if you can provide further evidence that this is a problem in Django.

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