#29266: Cannot perform schema migrations without downtime using MySQL in strict
mode
-------------------------------------+-------------------------------------
               Reporter:  Paul       |          Owner:  nobody
  Tiplady                            |
                   Type:  New        |         Status:  new
  feature                            |
              Component:  Database   |        Version:  2.0
  layer (models, ORM)                |
               Severity:  Normal     |       Keywords:
           Triage Stage:             |      Has patch:  0
  Unreviewed                         |
    Needs documentation:  0          |    Needs tests:  0
Patch needs improvement:  0          |  Easy pickings:  0
                  UI/UX:  0          |
-------------------------------------+-------------------------------------
 Performing schema migrations without downtime requires a fair bit of
 forethought, for example see

 http://pankrat.github.io/2015/django-migrations-without-downtimes/

 In summary, the process for adding a new field is:

 1. App and DB at version N
 2. Migrate DB schema to version N+1
 3. Update app server instances to version N+1

 Problem:

 At step 2, the version N app must be compatible with the N+1 database
 schema. This doesn't work in MySQL strict mode when adding many types of
 field - from my (non-exhaustive research):

 * a non-nullable field (e.g. `BooleanField`)
 * setting a nullable field to be non-nullable
 * setting a nullable field to have a default (e.g.
 `NullBooleanField(default=False)`)
 * any form of `CharField`

 since Django does not support setting default values in the DB. In MySQL
 strict mode, an insert that omits a value from a no-default field produces
 an error ("Field doesn't have a default value").

 This is not a problem in Rails, since that framework does write default
 values into the DB schema; for a look at zero-downtime schema migrations
 in Rails-land, see:

 https://samsaffron.com/archive/2018/03/22/managing-db-schema-changes-
 without-downtime

 Proposal:

 I'm sure this has been discussed previously but I can't find any
 justification in the docs for the design decision that Django does not
 write defaults to the DB; is there any room to revisit that decision? It
 does seems to make it challenging (and in many cases impossible) to
 perform hitless migrations, which is a big issue in the modern paradigm of
 continuous delivery.

 I would like to make it possible to write safe DB migrations without
 having to manually write SQL for every migration (since that negates a
 significant benefit of using Django's ORM, and is more error-prone).

 I'd be interested in other suggestions for how to achieve this, but I
 propose to add configuration to the BaseDatabaseSchemaEditor method to
 make it possible to leave the default value in the schema (e.g. to pass in
 a flag that would skip adding the "DROP DEFAULT" in add_field here:
 
https://github.com/django/django/blob/master/django/db/backends/base/schema.py#L420-L428).

 With that change in place there are a few possibilities for how to enable
 the new behaviour in an application --

 1. globally through a settings flag (this seems hacky as it wouldn't keep
 track of the state of existing fields in the schema)
 2. per-model class by adding a new Meta field specifying whether defaults
 should be written to the DB -- that way each model can be migrated
 individually and only as/when desired.

 There may be other options and there are definitely more details to flesh
 out, but I'll pause here as I'm sure there's plenty to discuss in the
 above.

 I should also add that I have some resource available to fix this issue
 that I'm seeing, and it's currently looking like I'll have to carry
 patched versions of the DatabaseSchemaEditor code (unless there's a way of
 avoiding changes to core Django that I'm missing). I'd be happy to work
 with you guys to shape these changes and contribute them back if there is
 interest in improving the story for zero-downtime migrations in the ORM.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/29266>
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 post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/054.12f4eb4f1d19584ede759d0ce9b33dbf%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to