Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Ten artykuł wyjaśnia, jak system migracji Django współpracuje z SQL Server za pośrednictwem zaplecza mssql-django, oraz opisuje przypadki brzegowe.
Tworzenie i stosowanie migracji
Proces migracji w Django działa tak samo w przypadku SQL Server jak w przypadku innych baz danych:
Generowanie migracji na podstawie zmian modelu:
python manage.py makemigrations myappPrzejrzyj wygenerowane pliki migracji w pliku
<app>/migrations/.Zastosuj migracje do bazy danych:
python manage.py migrate myappSprawdź stan migracji:
python manage.py showmigrations myapp
Początkowa konfiguracja projektu
Podczas konfigurowania nowego projektu Django przy użyciu SQL Server uruchom migracje, aby utworzyć wbudowane tabele Django (uwierzytelnianie, sesje, administrator):
python manage.py migrate
To polecenie tworzy wszystkie tabele wymagane przez aplikacje wymienione w INSTALLED_APPS.
Niestandardowy kod SQL w migracjach
Służy migrations.RunSQL do wykonywania nieprzetworzonych instrukcji SQL podczas migracji. Takie podejście jest przydatne w przypadku tworzenia procedur składowanych, wyzwalaczy lub innych obiektów specyficznych dla SQL Server:
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;",
),
]
Przypadki brzegowe migracji
Poniższe operacje migracji wymagają zastosowania obejść w przypadku migracji ukierunkowanych na serwer SQL Server.
Modyfikacja AutoField
Zmiana pola modelu z lub do AutoField w czasie migracji nie jest obsługiwana. SQL Server nie zezwala na dodawanie ani usuwanie IDENTITY właściwości z istniejącej kolumny.
Obejście problemu: Utwórz nowy model z wybranym typem pola. Zmigruj dane ze starej tabeli do nowej tabeli, a następnie upuść starą tabelę.
Zmienianie nazwy pola lub modelu przy użyciu ograniczeń klucza obcego
Zmiana nazwy pola lub modelu z ograniczeniami klucza obcego może zakończyć się niepowodzeniem. SQL Server wymaga porzucania i ponownego tworzenia ograniczeń FK podczas operacji zmiany nazwy.
Obejście: Użyj polecenia migrations.SeparateDatabaseAndState , aby usunąć ograniczenie FK, zmienić nazwę kolumny i ponownie utworzyć ograniczenie, informując Django o zaktualizowanie stanu modelu. Poniższy przykład zmienia nazwę klucza obcego product w modelu Order na nazwę 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",
),
],
),
]
Przed uruchomieniem tego kodu Transact-SQL (T-SQL) sprawdź faktyczną nazwę ograniczenia w swojej bazie danych. Django generuje nazwy ograniczeń, które zawierają krótki skrót, więc nazwa w schemacie nie jest zgodna z symbolem zastępczym pokazanym tutaj.
Działania referencyjne na poziomie bazy danych
Django 6.1 dodaje referencyjne działania na poziomie bazy danych, takie jak DB_CASCADE, DB_SET_NULL, oraz DB_SET_DEFAULT. SQL Server odrzuca wykresy kluczy obcych z wieloma ścieżkami kaskadowymi prowadzącymi do tej samej tabeli, więc mssql-django nie obsługuje tych wartości w żadnej wersji SQL Server. Użycie jednej z tych wartości wywołuje kontrolę systemową Django fields.E324. Zamiast tego użyj standardowego zachowania na poziomie on_delete Django.
Agregaty bitowe
Django 6.1 dodaje BitAnd, BitOr, oraz BitXor. SQL Server nie posiada natywnej funkcji agregacji bitowej i mssql-django nie emuluje tych agregatów. Nazywanie ich podnosi NotSupportedError.
Migracje do usługi Squash
Po nagromadzeniu wielu migracji można je scalić do mniejszej liczby plików:
python manage.py squashmigrations myapp 0001 0010
Tip
Zawsze przetestuj migracje w trybie squasha względem nowej bazy danych, aby upewnić się, że tworzą prawidłowy schemat.
Wygenerowane kolumny (kolumny obliczane)
Backend mssql-django obsługuje element GeneratedField w Django, który odpowiada kolumnom obliczanym w SQL Server.
Kolumny generowane przechowywane (PERSISTED)
Przechowywana wygenerowana kolumna jest fizycznie zapisywana na dysku i aktualizowana po zmianie kolumn źródłowych:
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,
)
Spowoduje to wygenerowanie: [total_price] AS (([price] * (1 + [tax_rate]))) PERSISTED. SQL Server normalizuje wyrażenie podczas jego zapisu, więc sys.computed_columns raportuje ([price]*((1)+[tax_rate])).
Wirtualne kolumny generowane
Kolumna wygenerowana wirtualnie jest obliczana w czasie wykonywania zapytań i nie korzysta z magazynu:
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 ogranicza możliwość tworzenia indeksów na nieutrwalonych kolumnach obliczeniowych. Użyj db_persist=True polecenia , jeśli musisz zaindeksować wygenerowaną kolumnę.
Komentarze do tabel i kolumn
Backend mssql-django wspiera funkcję Django db_comment w wspieranych wersjach Django. Komentarze są przechowywane jako MS_Description właściwości rozszerzone obiektu SQL Server.
Komentarze do tabeli
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."
Komentarze kolumn
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")
Komentarze są widoczne w SQL Server Management Studio w obszarze właściwości kolumny/tabeli i za pomocą polecenia sys.extended_properties.
Złożone klucze podstawowe
W Django 5.2 wprowadzono CompositePrimaryKey. Zaplecze mssql-django ma częściową obsługę złożonych kluczy podstawowych, ale niektóre przypadki testowe Django są nadal wykluczone. Przed wdrożeniem ich w środowisku produkcyjnym zweryfikuj migracje i zapytania dotyczące klucza złożonego.
-
inspectdbnie generuje poprawnie złożonych kluczy podstawowych. Zdefiniuj je ręcznie po inspekcji. - Wyszukiwanie w krotkach nie jest obsługiwane. Backend rozkłada porównania kluczy kompozytowych na warunki dla poszczególnych kolumn.
- Porównywanie krotek z podzapytaniami wymaga Django 5.2.4 lub nowszej wersji.
- Niektóre operacje migracji nadal mają znane wykluczenia. Aktualny stan znajduje się w Ograniczeniach i nieobsługiwanych funkcjach w mssql-django.
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 obsługa
W przypadku wstawiania jawnych wartości do elementu AutoField (na przykład przywracania danych z kopii zapasowej przy użyciu określonych identyfikatorów) zaplecze automatycznie opakowuje wstawianie w pliku SET IDENTITY_INSERT ON / SET IDENTITY_INSERT OFF. Nie jest wymagana żadna ręczna baza danych SQL.
# The backend handles IDENTITY_INSERT automatically
Product.objects.create(id=42, name="Restored Widget", price=9.99)
Note
SQL Server pozwala, aby w danej sesji tylko jedna tabela miała w danym momencie IDENTITY_INSERT ON. Jeśli wstawisz jawnie określone identyfikatory do wielu tabel w obrębie jednego bloku atomic(), backend obsługuje to przełączanie osobno dla każdej instrukcji. Jednak współbieżne sesje, które również używają IDENTITY_INSERT na tej samej tabeli, mogą powodować konflikty.