Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
In diesem Artikel wird erläutert, wie das Migrationssystem von Django mit SQL Server über das mssql-django Backend funktioniert, und bekannte Randfälle werden dokumentiert.
Erstellen und Anwenden von Migrationen
Djangos Migrationsworkflow funktioniert auf die gleiche Weise mit SQL Server wie mit anderen Datenbanken:
Generieren Sie Migrationen aus Änderungen am Modell:
python manage.py makemigrations myappÜberprüfen Sie die generierten Migrationsdateien in
<app>/migrations/.Migrationen auf die Datenbank anwenden:
python manage.py migrate myappMigrationsstatus überprüfen:
python manage.py showmigrations myapp
Anfängliches Projektsetup
Wenn Sie ein neues Django-Projekt mit SQL Server einrichten, führen Sie Migrationen aus, um integrierte Django-Tabellen zu erstellen (Authentifizierung, Sitzungen, Administrator):
python manage.py migrate
Mit diesem Befehl werden alle Tabellen erstellt, die für die in INSTALLED_APPS aufgeführten Apps erforderlich sind.
Benutzerdefiniertes SQL in Migrationen
Verwenden Sie migrations.RunSQL, um während der Migrationen rohe SQL-Anweisungen auszuführen. Dieser Ansatz eignet sich zum Erstellen gespeicherter Prozeduren, Trigger oder anderer SQL Server spezifischer Objekte:
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("myapp", "0001_initial"),
]
operations = [
migrations.RunSQL(
sql="CREATE INDEX IX_myapp_product_name ON myapp_product (name);",
reverse_sql="DROP INDEX IX_myapp_product_name ON myapp_product;",
),
]
Bekannte Migrationsgrenzfälle
Die folgenden Migrationsvorgänge erfordern Workarounds, wenn SQL Server als Ziel verwendet wird.
AutoField-Änderung
Das Ändern eines Modellfelds von oder zu AutoField während der Migration wird nicht unterstützt. SQL Server lässt das Hinzufügen oder Entfernen der IDENTITY Eigenschaft aus einer vorhandenen Spalte nicht zu.
Problemumgehung: Erstellen Eines neuen Modells mit dem gewünschten Feldtyp. Migrieren Sie Daten aus der alten Tabelle zur neuen Tabelle, und legen Sie dann die alte Tabelle ab.
Umbenennen von Feld oder Modell mit Fremdschlüsseleinschränkungen
Das Umbenennen eines Felds oder Modells mit Fremdschlüsseleinschränkungen kann fehlschlagen. SQL Server erfordert das Löschen und Neuerstellen von FK-Constraints bei Umbenennungen.
Problemumgehung: Verwenden Sie migrations.SeparateDatabaseAndState, um den FK-Constraint zu löschen, die Spalte umzubenennen und den Constraint neu zu erstellen, und weisen Sie Django dabei an, seinen Modellstatus zu aktualisieren. Im folgenden Beispiel wird der product Fremdschlüssel in einem Order Modell umbenannt in item:
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("myapp", "0002_previous"),
]
operations = [
migrations.SeparateDatabaseAndState(
database_operations=[
migrations.RunSQL(
sql="ALTER TABLE myapp_order DROP CONSTRAINT FK_order_product;",
reverse_sql="ALTER TABLE myapp_order ADD CONSTRAINT FK_order_product FOREIGN KEY (product_id) REFERENCES myapp_product(id);",
),
migrations.RunSQL(
sql="EXECUTE sp_rename 'myapp_order.product_id', 'item_id', 'COLUMN';",
reverse_sql="EXECUTE sp_rename 'myapp_order.item_id', 'product_id', 'COLUMN';",
),
migrations.RunSQL(
sql="ALTER TABLE myapp_order ADD CONSTRAINT FK_order_item FOREIGN KEY (item_id) REFERENCES myapp_product(id);",
reverse_sql="ALTER TABLE myapp_order DROP CONSTRAINT FK_order_item;",
),
],
state_operations=[
migrations.RenameField(
model_name="order",
old_name="product",
new_name="item",
),
],
),
]
Suchen Sie den tatsächlichen Einschränkungsnamen in Ihrer Datenbank, bevor Sie diesen T-SQL-Code ausführen. Django generiert Einschränkungsnamen, die einen kurzen Hash enthalten, sodass der Name in Ihrem Schema nicht mit dem hier gezeigten Platzhalter übereinstimmt.
Migrationen zusammenfassen
Nachdem sich viele Migrationen angesammelt haben, können Sie sie in einer kleineren Anzahl von Dateien zusammenfassen:
python manage.py squashmigrations myapp 0001 0010
Tip
Testen Sie zusammengeführte Migrationen immer mit einer neuen Datenbank, um sicherzustellen, dass sie das korrekte Schema erzeugen.
Generierte Spalten (berechnete Spalten)
Das mssql-django Backend unterstützt Djangos GeneratedField (Django 5.0 und höher), die SQL Server-berechneten Spalten entsprechen.
Gespeicherte (PERSISTED) generierte Spalten
Eine gespeicherte generierte Spalte wird physisch auf den Datenträger geschrieben und aktualisiert, wenn sich die Quellspalten ändern:
from django.db import models
from django.db.models import F
class Product(models.Model):
price = models.DecimalField(max_digits=10, decimal_places=2)
tax_rate = models.DecimalField(max_digits=5, decimal_places=4)
total_price = models.GeneratedField(
expression=F("price") * (1 + F("tax_rate")),
output_field=models.DecimalField(max_digits=10, decimal_places=2),
db_persist=True,
)
Dies generiert: total_price AS ([price] * (1 + [tax_rate])) PERSISTED.
Virtuelle generierte Spalten
Eine virtuelle generierte Spalte wird zur Abfragezeit berechnet und verbraucht keinen Speicher:
from django.db import models
from django.db.models import F, Value
from django.db.models.functions import Concat
class Employee(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
full_name = models.GeneratedField(
expression=Concat(F("first_name"), Value(" "), F("last_name")),
output_field=models.CharField(max_length=101),
db_persist=False,
)
Note
SQL Server schränkt Indizes für nicht persistierte berechnete Spalten ein. Verwenden Sie db_persist=True, wenn Sie die generierte Spalte indizieren müssen.
Tabellen- und Spaltenkommentare
Das mssql-django Back-End unterstützt Djangos db_comment Feature (Django 4.2 und höher). Kommentare werden als MS_Description erweiterte Eigenschaften für das SQL Server-Objekt gespeichert.
Tabellenkommentare
class AuditLog(models.Model):
action = models.CharField(max_length=50)
timestamp = models.DateTimeField(auto_now_add=True)
class Meta:
db_table_comment = "Tracks user actions for compliance auditing."
Spaltenkommentare
class Measurement(models.Model):
value = models.FloatField(db_comment="Sensor reading in Celsius")
recorded_at = models.DateTimeField(db_comment="UTC timestamp from the data logger")
Kommentare sind in SQL Server Management Studio unter den Spalten- bzw. Tabelleneigenschaften und über sys.extended_properties sichtbar.
Zusammengesetzte Primärschlüssel
Django 5.2 führte CompositePrimaryKey ein. Das mssql-django Back-End unterstützt teilweise zusammengesetzte Primärschlüssel, aber einige Django-Testfälle sind weiterhin ausgeschlossen. Validieren Sie Migrationen mit zusammengesetzten Schlüsseln und Abfragen in Ihrer Anwendung, bevor Sie sie in der Produktion einsetzen.
-
inspectdbgeneriert zusammengesetzte Primärschlüssel nicht korrekt. Definieren Sie sie manuell nach der Inspektion. - Tupelabfragen werden nicht unterstützt. Das Back-End zerlegt zusammengesetzte Schlüsselvergleiche in einzelne Spaltenbedingungen.
- Tupelvergleiche mit Unterabfragen erfordern Django 5.2.4 und neuere Versionen.
- Einige Migrationsvorgänge weisen noch bekannte Ausschlüsse auf. Siehe Einschränkungen und nicht unterstützte Features in mssql-django für den aktuellen Status.
from django.db import models
from django.db.models import CompositePrimaryKey
class OrderItem(models.Model):
pk = CompositePrimaryKey("order_id", "product_id")
order = models.ForeignKey("Order", on_delete=models.CASCADE)
product = models.ForeignKey("Product", on_delete=models.CASCADE)
quantity = models.IntegerField()
IDENTITY_INSERT Handhabung
Wenn Sie explizite Werte in eine AutoField (z. B. das Wiederherstellen von Daten aus einer Sicherung mit bestimmten IDs) einfügen, schließt das Back-End das Einfügen automatisch umSET IDENTITY_INSERT ON / SET IDENTITY_INSERT OFF. Es ist kein manuelles SQL erforderlich.
# The backend handles IDENTITY_INSERT automatically
Product.objects.create(id=42, name="Restored Widget", price=9.99)
Note
SQL Server lässt zu, dass jeweils nur eine Tabelle pro Sitzung gleichzeitig über IDENTITY_INSERT ON verfügt. Wenn Sie in einem einzigen atomic()-Block explizite IDs in mehrere Tabellen einfügen, behandelt das Backend das Umschalten für jede Anweisung einzeln. Es kann jedoch zu Konflikten mit gleichzeitigen Sessions kommen, die ebenfalls IDENTITY_INSERT in derselben Tabelle verwenden.