python / expert
Snippet
Django Datenbank Migrations mit Custom Operations
Django Migrations unterstützen Custom Operations für komplexe Datentransformationen, die über einfache Feldänderungen hinausgehen. Dieses Pattern ist unerlässlich, wenn Daten zwischen Tabellen migriert, Batch-Verarbeitung während Migrations durchgeführt oder Zero-Downtime-Migrationsstrategien implementiert werden müssen. Die MoveDataToNewTable-Operation demonstriert, wie durch große Datensätze in Batches iteriert, benutzerdefinierte Logik auf jedem Datensatz ausgeführt und Datenbankkonsistenz mit atomaren Transaktionen gewährleistet wird.
snippet.py
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
45
from django.db import migrationsclass MoveDataToNewTable(migrations.Operation):atomic = Truedef __init__(self, model_name, field_name, batch_size=1000):self.model_name = model_nameself.field_name = field_nameself.batch_size = batch_sizedef state_forwards(self, app_label, state):passdef database_forwards(self, app_label, schema_editor, from_state, to_state):model = state.get_model(app_label, self.model_name)field = model._meta.get_field(self.field_name)queryset = model.objects.filter(**{f'{self.field_name}__isnull': False})total = queryset.count()for offset in range(0, total, self.batch_size):batch = list(queryset[offset:offset + self.batch_size])for obj in batch:field.save(obj, obj)schema_editor.execute('SELECT 1')def describe(self):return f'Migrating {self.field_name} data in {self.model_name}'class Migration(migrations.Migration):dependencies = [('myapp', '0001_initial')]operations = [migrations.AddField(model_name='product',name='cached_slug',field=models.SlugField(max_length=150, null=True),),MoveDataToNewTable('product', 'cached_slug'),migrations.AlterField(model_name='product',name='cached_slug',field=models.SlugField(max_length=150),),]
django
Erklärung
1
class MoveDataToNewTable(migrations.Operation):
Custom Migration-Operations-Klasse erbt von migrations.Operation
2
atomic = True
Klassenattribut stellt sicher, dass Operation in Transaktion läuft
3
def database_forwards(self, app_label, schema_editor, from_state, to_state):
Hauptmethode, die während der Migration aufgerufen wird
4
queryset.filter(**{f'{self.field_name}__isnull': False})
Dynamisches Feldfiltern mittels Dictionary Unpacking
5
for offset in range(0, total, self.batch_size):
Batch-Iterations-Pattern für speichereffiziente Verarbeitung großer Datensätze
6
schema_editor.execute('SELECT 1')
Dummy-Query um Batch-Commit in PostgreSQL/MySQL auszulösen