Adatbázis-migrálások az mssql-django használatával

Ez a cikk bemutatja, hogyan működik a Django migrációs rendszere az SQL Servert kezelő mssql-django háttérrendszeren keresztül, és dokumentálja az ismert speciális eseteket.

Migrálások létrehozása és alkalmazása

A Django migrálási munkafolyamata ugyanúgy működik a SQL Server, mint más adatbázisokkal:

  1. Migrálások létrehozása modellmódosításokból:

    python manage.py makemigrations myapp
    
  2. Tekintse át a létrehozott migrációs fájlokat itt: <app>/migrations/.

  3. Migrálás alkalmazása az adatbázisra:

    python manage.py migrate myapp
    
  4. A migrálás állapotának ellenőrzése:

    python manage.py showmigrations myapp
    

Kezdeti projektbeállítás

Amikor új Django-projektet állít be SQL Server használatával, futtassa a migrációkat a Django beépített tábláinak (hitelesítés, munkamenetek, adminisztráció) létrehozásához:

python manage.py migrate

Ez a parancs létrehozza a listában felsorolt alkalmazásokhoz szükséges összes táblát INSTALLED_APPS.

Egyéni SQL a migrálásokban

A migrálás során nyers SQL-utasítások végrehajtására használható migrations.RunSQL . Ez a módszer tárolt eljárások, eseményindítók vagy más SQL Server-specifikus objektumok létrehozásához hasznos:

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;",
        ),
    ]

Ismert migrációs szélső esetek

Az alábbi migrálási műveletek kerülőmegoldásokat igényelnek, ha a cél az SQL Server.

Automatikus mező módosítása

A modellmezőnek a migrálás során AutoField típusról vagy típusra történő módosítása nem támogatott. SQL Server nem engedélyezi a IDENTITY tulajdonság hozzáadását vagy eltávolítását egy meglévő oszlopból.

Megkerülő megoldás: Hozzon létre egy új modellt a kívánt mezőtípussal. A régi táblából az új táblába migrálhatja az adatokat, majd elveti a régi táblát.

Mező vagy modell átnevezése idegenkulcs-korlátozásokkal

Az idegenkulcs-korlátozásokkal rendelkező mezők vagy modellek átnevezése sikertelen lehet. SQL Server FK-korlátozások elvetését és újrakonformálását igényli az átnevezési műveletek során.

Megkerülő megoldás: Az FK-kényszer elvetésére, az oszlop átnevezésére és a kényszer újbóli létrehozására használható migrations.SeparateDatabaseAndState , miközben a Django-t arra utasítja, hogy frissítse a modell állapotát. Az alábbi példa átnevezi a product modell idegen kulcsát Order a következőre 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",
                ),
            ],
        ),
    ]

A T-SQL-kód futtatása előtt keresse meg az adatbázis tényleges kényszernevét. A Django rövid kivonatot tartalmazó kényszerneveket hoz létre, így a séma neve nem egyezik az itt látható helyőrzővel.

Migrációk összevonása

Miután sok migrálás halmozódott fel, kevesebb fájlba gyűjtheti őket:

python manage.py squashmigrations myapp 0001 0010

Tip

A tömörített migrációkat mindig tesztelje egy új adatbázison, annak biztosítására, hogy azok a megfelelő sémát eredményezzék.

Generált oszlopok (számított oszlopok)

A mssql-django backend támogatja a Django GeneratedField funkcióját (a Django 5.0-s és újabb verzióiban), amely az SQL Server számított oszlopainak felel meg.

Tárolt (TARTÓS) generált oszlopok

A tárolt generált oszlopok fizikailag a lemezre lesznek írva, és a forrásoszlopok változásakor frissülnek:

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,
    )

Ez a következőt hozza létre: total_price AS ([price] * (1 + [tax_rate])) PERSISTED.

Virtuálisan létrehozott oszlopok

A virtuálisan létrehozott oszlopokat a rendszer lekérdezéskor számítja ki, és nem használja fel a tárterületet:

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

Az SQL Server korlátozza az indexek létrehozását a nem perzisztált számított oszlopokon. Akkor használja db_persist=True , ha indexelnie kell a létrehozott oszlopot.

Táblázat- és oszlopbejegyzések

A mssql-django háttérrendszer támogatja a Django funkcióját db_comment (Django 4.2 és újabb verziók). A megjegyzések kiterjesztett tulajdonságokként MS_Description vannak tárolva az SQL Server objektumon.

Táblázat megjegyzései

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."

Oszlop megjegyzései

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")

A megjegyzések SQL Server Management Studio oszlop-/táblatulajdonságok alatt és a területen sys.extended_propertiesláthatók.

Összetett elsődleges kulcsok

Django 5.2 bevezetett CompositePrimaryKey. A mssql-django háttérrendszer részlegesen támogatja az összetett elsődleges kulcsokat, de néhány Django-teszteset továbbra is ki van zárva. Ellenőrizze az összetett kulcsú migrálásokat és lekérdezéseket az alkalmazáson, mielőtt éles környezetben bevezeti őket.

  • inspectdb nem hozza létre megfelelően az összetett elsődleges kulcsokat. Az ellenőrzés után manuálisan definiálhatja őket.
  • A Tuple-keresések nem támogatottak. A háttérrendszer az összetett kulcsok összehasonlítását különálló oszlopfeltételekre bontja.
  • A tuple-ök albekérdezésekkel való összehasonlításához a Django 5.2.4-es vagy újabb verziója szükséges.
  • Egyes áttelepítési műveletek továbbra is ismert kizárásokkal rendelkeznek. Tekintse meg az mssql-django jelenlegi állapotának korlátozásait és nem támogatott funkcióit .
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 Kezelése

Amikor explicit értékeket szúr be egy AutoField fájlba (például egy adott azonosítóval rendelkező biztonsági másolat adatainak visszaállítása), a háttérrendszer automatikusan becsomagolja a beszúrást SET IDENTITY_INSERT ON / SET IDENTITY_INSERT OFF. Nincs szükség manuális SQL-re.

# The backend handles IDENTITY_INSERT automatically
Product.objects.create(id=42, name="Restored Widget", price=9.99)

Note

A SQL Server munkamenetenként egyszerre csak egy táblán engedélyezi a(z) IDENTITY_INSERT ON használatát. Ha explicit azonosítókat illeszt be több táblába egyetlen atomic() blokkban, a backend utasításonként kezeli az átváltást. Az ugyanazon a táblán is használt IDENTITY_INSERT egyidejű munkamenetek azonban ütközhetnek.