Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Bu makale, PostgreSQL 'den ( veya psycopg2) SQL Serverpsycopg (mssql-django) 'e taşınan Django uygulamaları için ayrıntılı bir geçiş kılavuzudur. Herhangi bir veritabanından geçişe genel bir genel bakış için bkz. Django uygulamalarını diğer veritabanlarından SQL Server geçirme.
Prerequisites
- Python 3.8 veya üzeri
- Microsoft SQL Server için ODBC Sürücüsü 17 veya 18. Bkz . mssql-django'yu yükleme.
- SQL Server 2016 veya üzeri ya da Azure SQL Veritabanı
Veritabanı arka ucunu değiştir
PostgreSQL yapılandırmanızı settings.py içinde değiştirin:
# Before (PostgreSQL)
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": "mydb",
"USER": "myuser",
"PASSWORD": "mypassword",
"HOST": "localhost",
"PORT": "5432",
},
}
# After (SQL Server)
DATABASES = {
"default": {
"ENGINE": "mssql",
"NAME": "mydb",
"USER": "myuser",
"PASSWORD": "mypassword",
"HOST": "localhost",
"PORT": "1433",
"OPTIONS": {
"driver": "ODBC Driver 18 for SQL Server",
},
},
}
Güncelle requirements.txt:
# Remove
# psycopg2-binary>=2.9
# or psycopg[binary]>=3.1
# Add
mssql-django>=1.5
django.contrib.postgres özelliklerini değiştirme
Modül PostgreSQL'e django.contrib.postgres özgü alanlar, işlevler ve aramalar sağlar. Bunlar SQL Server ile çalışmaz. Aşağıdaki bölümler, her bir özelliğin nasıl değiştirileceğini gösterir.
ArrayField
PostgreSQL ArrayField dizileri yerel olarak depolar. SQL Server bir dizi sütun türüne sahip değildir.
Seçenek 1: JSONField (Django 3.2 ve sonraki sürümlerle çalışır)
# Before
from django.contrib.postgres.fields import ArrayField
class Product(models.Model):
tags = ArrayField(models.CharField(max_length=50), default=list)
# After
class Product(models.Model):
tags = models.JSONField(default=list)
Değişiklikleri sorgulama:
# Before (PostgreSQL)
Product.objects.filter(tags__contains=["sale"])
Product.objects.filter(tags__overlap=["sale", "new"])
Product.objects.filter(tags__len=3)
# After (SQL Server with JSONField)
# Use __contains for exact list matching
Product.objects.filter(tags__contains=["sale"])
# For overlap-style queries, use raw SQL
from django.db.models.expressions import RawSQL
Product.objects.filter(
pk__in=RawSQL(
"""
SELECT p.id FROM products_product p
CROSS APPLY OPENJSON(p.tags) t
WHERE t.value IN (%s, %s)
""",
["sale", "new"],
)
)
Seçenek 2: İlgili tablo (normalleştirilmiş, büyük diziler veya sık filtreleme için daha iyi)
class Product(models.Model):
name = models.CharField(max_length=200)
class ProductTag(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name="tags")
tag = models.CharField(max_length=50, db_index=True)
class Meta:
unique_together = [("product", "tag")]
HStoreField
JSONField ile değiştirin:
# Before
from django.contrib.postgres.fields import HStoreField
class Profile(models.Model):
metadata = HStoreField(default=dict)
# After
class Profile(models.Model):
metadata = models.JSONField(default=dict)
JSONField aynı anahtar arama söz dizimini destekler:
# Both backends support this
Profile.objects.filter(metadata__theme="dark")
Aralık alanları
PostgreSQL aralık türlerinin (IntegerRangeField, BigIntegerRangeField, DateRangeField, DateTimeRangeField, ) DecimalRangeFieldSQL Server eşdeğeri yoktur. İki ayrı alan kullanın:
# Before
from django.contrib.postgres.fields import DateRangeField
class Event(models.Model):
dates = DateRangeField()
# After
class Event(models.Model):
start_date = models.DateField()
end_date = models.DateField()
Sorguları ayrı alan karşılaştırmaları kullanacak şekilde güncelleştirin. Daha önce PostgreSQL ile DateRangeField:
from django.contrib.postgres.fields import DateRangeField
from psycopg2.extras import DateRange
Event.objects.filter(dates__contains=DateRange(start, end))
Ardından, SQL Server’da iki DateField sütunla:
from datetime import date
start = date(2026, 1, 1)
end = date(2026, 12, 31)
Event.objects.filter(start_date__lte=start, end_date__gte=end)
CITextField ve CIEmailField
PostgreSQL'in büyük/küçük harfe duyarlı olmayan metin türleri uzantıyı citext kullanır. SQL Server’ın varsayılan harmanlaması (SQL_Latin1_General_CP1_CI_AS) zaten büyük/küçük harfe duyarsızdır, bu nedenle standart CharField ve EmailField aynı şekilde davranır:
# Before
from django.contrib.postgres.fields import CITextField
class Tag(models.Model):
name = CITextField(max_length=100)
# After - already case-insensitive with default SQL Server collation
class Tag(models.Model):
name = models.CharField(max_length=100)
SearchVector, SearchQuery, SearchRank
PostgreSQL tam metin arama, Django ile derin bir şekilde tümleşiktir. SQL Server kendi tam metin arama altyapısına sahiptir ancak Django ORM tümleştirmesi yoktur. Bu makalenin devamında tam metin arama geçişi bölümüne bakın.
Toplama işlevleri
PostgreSQL'e özgü toplamları değiştirin:
# Before
from django.contrib.postgres.aggregates import ArrayAgg, StringAgg
Product.objects.values("category").annotate(
all_names=ArrayAgg("name"),
name_list=StringAgg("name", delimiter=", "),
)
# After - use SQL Server equivalents via RawSQL
from django.db.models.expressions import RawSQL
Product.objects.values("category").annotate(
name_list=RawSQL(
"STRING_AGG(name, ', ') WITHIN GROUP (ORDER BY name)",
[],
),
)
Note
STRING_AGGSQL Server 2017 veya üzeri ya da Azure SQL Veritabanı gerektirir.
Tam metin arama geçişi
PostgreSQL tam metin araması , tsvectorve tsquery dizinlerini kullanırGIN. SQL Server ayrı bir tam metin arama altyapısı vardır.
SQL Server'da tam metin aramayı etkinleştirme
-- Create a full-text catalog
CREATE FULLTEXT CATALOG [MyAppCatalog] AS DEFAULT;
-- Create a full-text index (table must have a unique index)
CREATE FULLTEXT INDEX ON [products_product]([name], [description])
KEY INDEX [PK_products_product]
WITH CHANGE_TRACKING AUTO;
Django’dan tam metin araması sorgulama
SQL Server CONTAINS ve FREETEXT işlevlerine erişmek için ham SQL kullanın:
from django.db.models.expressions import RawSQL
# Equivalent of PostgreSQL SearchVector + SearchQuery
def search_products(query):
return Product.objects.filter(
pk__in=RawSQL(
"""
SELECT p.id FROM products_product p
WHERE CONTAINS((p.name, p.description), %s)
""",
[query],
)
)
Dereceli sonuçlar için (eşdeğeri SearchRank):
def search_products_ranked(query):
return Product.objects.raw(
"""
SELECT p.*, ft.[RANK]
FROM products_product p
INNER JOIN CONTAINSTABLE(products_product, (name, description), %s) ft
ON p.id = ft.[KEY]
ORDER BY ft.[RANK] DESC
""",
[query],
)
Tam metin dizini bakım yönergesi
Geçiş sonrasında SQL Server tam metin dizinleri için bakım planlayın:
- Neredeyse gerçek zamanlı güncelleştirmeler için kullanın
CHANGE_TRACKING AUTO. - Toplu yükleme pencereleri için kullanın
CHANGE_TRACKING MANUAL, ardından tam bir popülasyon çalıştırın. -
sys.fulltext_indexesvesys.dm_fts_index_populationaracılığıyla tarama durumunu ve birikmiş işleri izleyin.
Durumu denetle:
SELECT
OBJECT_NAME(i.object_id) AS table_name,
i.change_tracking_state_desc,
i.has_crawl_completed,
i.crawl_type_desc
FROM sys.fulltext_indexes AS i;
Manuel izleme ile büyük veri yüklemelerinden sonra:
ALTER FULLTEXT INDEX ON [products_product] START FULL POPULATION;
Tip
Düşük trafikli pencereler sırasında tam metin dizinlerini yeniden oluşturun veya yeniden girin. Tam popülasyonlar büyük tablolarda pahalı olabilir.
Arama yöneticisi oluşturma
Temiz erişim için ham SQL'i bir yöneticiye sarmalama:
class ProductSearchManager(models.Manager):
def search(self, query):
if not query:
return self.none()
return self.filter(
pk__in=RawSQL(
"""
SELECT p.id FROM products_product p
WHERE CONTAINS((p.name, p.description), %s)
""",
[query],
)
)
class Product(models.Model):
name = models.CharField(max_length=200)
description = models.TextField()
objects = ProductSearchManager()
# Usage: Product.objects.search("mountain bike")
PostGIS ve uzamsal veriler
mssql-django GeoDjango GIS arka ucu içermez. PostgreSQL uygulamanız aracılığıyla django.contrib.gisPostGIS kullanıyorsa uzamsal sorguları SQL Server'de doğrudan Django ORM'ye geçiremezsiniz.
SQL Server yerel olarak coğrafya ve geometri veri türlerini destekler. Geçiş sonrasında uzamsal verilerle çalışmak için:
- Uzamsal verileri depolayın; bunu ham SQL kullanarak veya SQL Server'ın geography ya da geometry sütunlarına eşlenen özel model alanlarıyla yapın.
- SQL Server yerleşik uzamsal işlevleriyle ham SQL kullanarak uzamsal verileri sorgulayın:
from django.db import connection
with connection.cursor() as cursor:
cursor.execute(
"""
SELECT id, name
FROM stores
WHERE location.STDistance(geography::Point(%s, %s, 4326)) <= %s
""",
[latitude, longitude, radius_meters],
)
- Django'ya SQL Server uzamsal destek ekleyen veya ORM'yi diğer her şey için kullanırken uzamsal sorguları ham SQL olarak tutan üçüncü taraf kitaplıkları göz önünde bulundurun.
Note
Uygulamanız yoğun olarak GeoDjango uzamsal aramalarına bağlıysa geçiş maliyetini dikkatle değerlendirin. Uzamsal sorguları ham SQL'e taşımak için her GeoDjango uzamsal filtresinin yeniden yazılması gerekir.
Bağlantı havuzlama geçişi
PostgreSQL uygulamanız bağlantı havuzu için kullanıyorsa pgbouncer , bunu Django'nun yerleşik bağlantı yönetimi veya ODBC bağlantı havuzuyla değiştirin.
Django bağlantısını yeniden kullanma
DATABASES = {
"default": {
"ENGINE": "mssql",
"NAME": "<your-database>",
"HOST": "<your-server>",
"OPTIONS": {
"driver": "ODBC Driver 18 for SQL Server",
},
"CONN_MAX_AGE": 600, # Reuse connections for 10 minutes
"CONN_HEALTH_CHECKS": True, # Django 4.1+
},
}
Diğer ayrıntılar için bkz. mssql-django'da bağlantı havuzu oluşturma.
DISTINCT ON değiştirme
PostgreSQL, grup başına bir satır almayı destekler DISTINCT ON . SQL Server bu söz dizimlerini desteklemez. Bunun yerine pencere işlevlerini kullanın:
# Before (PostgreSQL)
Entry.objects.order_by("blog_id", "-pub_date").distinct("blog_id")
# After (SQL Server) - use raw SQL with ROW_NUMBER
Entry.objects.raw(
"""
SELECT * FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY blog_id ORDER BY pub_date DESC) AS rn
FROM blog_entry
) sub
WHERE rn = 1
"""
)
JSONB sorguları
PostgreSQL'in jsonb türü zengin sorgu işleçlerini destekler. SQL Server, SQL Server 2016'dan bu yana kullanılabilen sorgu işlevleriyle JSON'ı nvarchar(max) olarak depolar.
Django'nun JSONField arama söz dizimi, temel işlemler için her iki arka uçta da çalışır:
# Works on both PostgreSQL and SQL Server
Config.objects.filter(data__settings__theme="dark")
Config.objects.filter(data__has_key="settings")
Django'nun ORM'sinde desteklenmeyen gelişmiş JSON sorguları için SQL Server JSON_VALUE ve OPENJSON işlevlerini kullanın:
from django.db.models.expressions import RawSQL
# Query nested JSON values
Config.objects.annotate(
theme=RawSQL("JSON_VALUE(data, '$.settings.theme')", [])
).filter(theme="dark")
PostgreSQL bağımlılıklarını kaldırma
Geçişten sonra PostgreSQL paketlerini projenizden kaldırın:
pip uninstall psycopg2-binary psycopg2 psycopg
settings.py içinde INSTALLED_APPS öğesinden django.contrib.postgres öğesini kaldırın:
INSTALLED_APPS = [
# Remove this line:
# "django.contrib.postgres",
"django.contrib.admin",
"django.contrib.auth",
# ...
]
Geçiş denetim listesi
| Step | Details |
|---|---|
| Arka ucu değiştir |
settings.py içinde django.db.backends.postgresql yerine mssql yazın. |
| contrib.postgres'u değiştir |
ArrayField, HStoreField, aralık alanları ve CI alanlarının yerini değiştirin. |
| Tam metin arama güncelleştirme |
tsvector
/
tsquery öğesinden SQL Server CONTAINS/FREETEXT öğesine geçiş. |
| Uzamsal sorguları güncelleştirme | GeoDjango aramalarını, SQL Server uzamsal işlevleri kullanarak ham SQL olarak yeniden yaz. |
Değiştir DISTINCT ON |
Pencere işlevlerini kullanın ROW_NUMBER() . |
| Ham SQL'i güncelleştirme | PostgreSQL sözdizimini (LIMIT, ||, NOW()) SQL Server söz dizimi olarak değiştirin. Bkz . Özel SQL'i güncelleştirme. |
| RCSI'yi etkinleştirme | PostgreSQL MVCC davranışıyla eşleşecek şekilde ayarlayın READ_COMMITTED_SNAPSHOT ON . Bkz. İşlem yalıtımı farklılıkları. |
| Karşılaştırmayı test etme | Büyük/küçük harf duyarlılığı davranışının beklentilerinizle eşleştiğini doğrulayın. Bkz. Harmanlama farklılıkları. |
| psycopg2'yi kaldırma |
psycopg2-binary veya psycopg kaldırın. "Bu öğeyi kaldırın django.contrib.postgres." |
| Migrasyonları yeniden oluştur | Eski geçiş dosyalarını silin, çalıştırın makemigrations ve migrate yenileyin. |
| Verileri taşı | Büyük veri kümeleri için etl aracını kullanın dumpdata/loaddata . |