python / expert
Snippet
Django Datenbank-Migration Eigene Operation für Null-Ausfall Schemaänderungen
Diese eigene Migrationsoperation fügt Spalten mit Standardwerten sicher zu Produktionsdatenbanken hinzu, ohne Tabellenebene-Sperren zu verursachen. Sie verwendet einen Dreiphasen-Ansatz: Spalte mit Standardwert hinzufügen (schnell bei PostgreSQL), NULL-Werte nachtragen, dann NOT NULL-Constraint hinzufügen. Dieses Muster ist essentiell für Null-Ausfall-Bereitstellungen, wo langlaufende Tabellensperren inakzeptabel sind.
snippet.py
python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
from django.db import migrationsclass AddColumnWithDefaultOperation(migrations.Operation):"""Safe column addition that avoids table locks on production databases."""def __init__(self, model_name, column_name, default_value, column_type='varchar(255)'):self.model_name = model_nameself.column_name = column_nameself.default_value = default_valueself.column_type = column_typedef state_forwards(self, app_label, state):new_field = migrations.CharField(max_length=255, default=self.default_value)new_field.set_attributes_from_name(self.column_name)state.add_model(app_label, self.model_name)setattr(state.models[app_label, self.model_name], self.column_name, new_field)def database_forwards(self, app_label, schema_editor, connection):if connection.vendor == 'postgresql':with connection.cursor() as cursor:cursor.execute(f"""ALTER TABLE {self.model_name}ADD COLUMN IF NOT EXISTS {self.column_name} {self.column_type} DEFAULT %s""", [self.default_value])cursor.execute(f"""UPDATE {self.model_name} SET {self.column_name} = %s WHERE {self.column_name} IS NULL""", [self.default_value])cursor.execute(f"""ALTER TABLE {self.model_name} ALTER COLUMN {self.column_name} SET NOT NULL""")elif connection.vendor == 'mysql':with connection.cursor() as cursor:cursor.execute(f"""ALTER TABLE {self.model_name} ADD COLUMN {self.column_name} {self.column_type}""")cursor.execute(f"""UPDATE {self.model_name} SET {self.column_name} = %s WHERE {self.column_name} IS NULL""", [self.default_value])cursor.execute(f"""ALTER TABLE {self.model_name} MODIFY COLUMN {self.column_name} {self.column_type} NOT NULL""")def describe(self):return f"Add column {self.column_name} to {self.model_name} with default {self.default_value}"
django
Erklärung
1
class AddColumnWithDefaultOperation(migrations.Operation)
Eigene Operation-Unterklasse definiert reversible Migration für Spalten hinzufügen
2
def database_forwards(self, app_label, schema_editor, connection)
Anbieter-spezifische SQL-Implementierung für PostgreSQL- und MySQL-Datenbanken
3
ADD COLUMN IF NOT EXISTS ... DEFAULT %s
PostgreSQL: fügt Spalte mit Standardwert hinzu ohne Lesen/Schreiben bestehender Zeilen zu sperren
4
UPDATE ... SET ... WHERE ... IS NULL
Nachtragen bestehender Zeilen mit Standardwert vor dem Hinzufügen des NOT NULL-Constraints
5
ALTER COLUMN ... SET NOT NULL
Fügt NOT NULL-Constraint hinzu nachdem alle bestehenden Zeilen mit gültigen Daten nachträgt wurden