#36167: Default value in migrations allows None/NULL
-----------------------------------------+--------------------------
               Reporter:  ivasilyev1     |          Owner:  (none)
                   Type:  Uncategorized  |         Status:  assigned
              Component:  Uncategorized  |        Version:  5.1
               Severity:  Normal         |       Keywords:
           Triage Stage:  Unreviewed     |      Has patch:  1
    Needs documentation:  0              |    Needs tests:  0
Patch needs improvement:  0              |  Easy pickings:  0
                  UI/UX:  0              |
-----------------------------------------+--------------------------
 When adding/altering a non-null model field the prompt for default value
 allows user input of string `"None"`.  Django then creates a migration
 with `default_value=None` and everything seems ok.

 If there is existing data in the DB and the generated migration is
 attempted to be applied, a runtime constraint error will be thrown.

 Simple proof:

  - Create test model with `null=True` field

 {{{
 class TestModel(models.Model):
     test_field = models.TextField(null=True, help_text='Test field')
 }}}

 and `makemigrations` to create initial migration

 {{{
 class Migration(migrations.Migration):
     initial = True
     dependencies = [
     ]
     operations = [
         migrations.CreateModel(
             name='TestModel',
             fields=[
                 ('id', models.BigAutoField(auto_created=True,
 primary_key=True, serialize=False, verbose_name='ID')),
                 ('test_field', models.TextField(help_text='Test field',
 null=True)),
             ],
         ),
     ]
 }}}

 - Create any arbitrary dummy record

 {{{
 >>> from testapp.models import *
 >>> TestModel().save()
 >>> exit()
 }}}

 - Switch the field to `null=False` and `makemigrations` again, selecting
 the default value option and entering `None`

 {{{
 $ python3 manage.py makemigrations
 It is impossible to change a nullable field 'test_field' on testmodel to
 non-nullable without providing a default. This is because the database
 needs something to populate existing rows.
 Please select a fix:
  1) Provide a one-off default now (will be set on all existing rows with a
 null value for this column)
  2) Ignore for now. Existing rows that contain NULL values will have to be
 handled manually, for example with a RunPython or RunSQL operation.
  3) Quit and manually define a default value in models.py.
 Select an option: 1
 Please enter the default value as valid Python.
 The datetime and django.utils.timezone modules are available, so it is
 possible to provide e.g. timezone.now as a value.
 Type 'exit' to exit this prompt
 >>> None
 Migrations for 'testapp':
   testapp/migrations/0002_alter_testmodel_test_field.py
     ~ Alter field test_field on testmodel
 }}}

 which creates the following migration without error

 {{{
     operations = [
         migrations.AlterField(
             model_name="testmodel",
             name="test_field",
             field=models.TextField(default=None, help_text="Test field"),
             preserve_default=False,
         ),
     ]
 }}}

 - Apply the new migration with `migrate`

 {{{
 python3 manage.py migrate
 Operations to perform:
   Apply all migrations: admin, auth, contenttypes, sessions, testapp
 Running migrations:
   Applying testapp.0002_alter_testmodel_test_field...Traceback (most
 recent call last):
 ...
 django.db.utils.IntegrityError: column "test_field" of relation
 "testapp_testmodel" contains null values
 }}}


 A bit of an edge case because if there is no data present in the table it
 seems to work fine. But the combination of `default=None` doesn't really
 make sense to be allowed in the first place if the goal is to prevent NULL
 values.

 The default value prompter should probably not allow this input
-- 
Ticket URL: <https://code.djangoproject.com/ticket/36167>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion visit 
https://groups.google.com/d/msgid/django-updates/01070194cec316ba-602867f5-291c-416d-bec9-461020ffdb4f-000000%40eu-central-1.amazonses.com.

Reply via email to