Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
This article documents how Django model field types map to SQL Server data types when using the mssql-django backend.
Field type mapping table
| Django field | SQL Server type | Notes |
|---|---|---|
AutoField |
int with IDENTITY(1,1) |
Auto-incrementing primary key. |
BigAutoField |
bigint with IDENTITY(1,1) |
64-bit auto-incrementing primary key. |
SmallAutoField |
smallint with IDENTITY(1,1) |
16-bit auto-incrementing primary key. |
BooleanField |
bit | Stores 0 or 1. |
CharField(max_length=N) |
nvarchar(N) | Unicode character data. |
DateField |
date | Date without time. |
DateTimeField |
datetime2 | Date and time with fractional seconds. Uses datetimeoffset when USE_TZ=True. |
DecimalField(max_digits=M, decimal_places=D) |
numeric(M, D) | Fixed-precision decimal. |
DurationField |
bigint | Stored as microseconds. |
EmailField |
nvarchar(254) | CharField with email validation. |
FileField |
nvarchar(100) | Stores the file path. |
FilePathField |
nvarchar(100) | Stores the file system path. |
FloatField |
float | 64-bit floating point (float(53)). SQL Server also accepts the synonym double precision. |
IntegerField |
int | 32-bit signed integer. |
BigIntegerField |
bigint | 64-bit signed integer. |
SmallIntegerField |
smallint | 16-bit signed integer. |
PositiveIntegerField |
int | With a CHECK constraint >= 0. |
PositiveBigIntegerField |
bigint | With a CHECK constraint >= 0. |
PositiveSmallIntegerField |
smallint | With a CHECK constraint >= 0. |
GenericIPAddressField |
nvarchar(39) | IPv4 or IPv6 address. |
JSONField |
nvarchar(max) | With JSON check constraint. Requires SQL Server 2016+. |
SlugField |
nvarchar(50) | CharField with slug validation. |
TextField |
nvarchar(max) | Unlimited-length Unicode text. |
TimeField |
time | Time without date. |
URLField |
nvarchar(200) | CharField with URL validation. |
UUIDField |
char(32) | UUID stored as 32-character hex string. |
BinaryField |
varbinary(N) | Raw binary data. The backend uses max_length to emit varbinary(N). |
ForeignKey |
Same as referenced field | Creates an index and FK constraint. |
OneToOneField |
Same as referenced field | Creates a unique index and FK constraint. |
ManyToManyField |
N/A | Creates an intermediate table. |
SQL Server-specific behaviors
Some Django field types have platform-specific behavior when used with SQL Server.
AutoField limitation
Altering a model field from or to AutoField at migration time isn't supported. If you need to change the primary key type, create a new field and migrate data manually.
BooleanField and bit
SQL Server bit type stores 0 and 1. Django maps True/False to these values. NULL is supported with BooleanField(null=True).
DateTimeField and time zone support
When USE_TZ=True in your Django settings, DateTimeField uses datetimeoffset to store time zone-aware datetimes. When USE_TZ=False, it uses datetime2.
If you enable USE_TZ after creating columns, you must manually migrate existing datetime2 columns to datetimeoffset. For more information, see Time zone support in mssql-django.
TextField vs CharField
SQL Server maps both TextField and CharField to nvarchar. TextField uses nvarchar(max) while CharField uses nvarchar(N) where N is max_length.
All string fields use nvarchar (Unicode)
The mssql-django backend maps all Django string fields (CharField, TextField, EmailField, URLField, SlugField, and others) to nvarchar, the Unicode string type. There's no built-in option to use varchar (non-Unicode) instead.
This is by design. Django's string handling is Unicode throughout, and nvarchar ensures that all characters are stored correctly regardless of language or encoding. Using nvarchar avoids data loss from character set mismatches.
Trade-offs:
- nvarchar uses 2 bytes per character, compared to 1 byte per character for varchar with single-byte collations.
- Index key size limits apply (900 bytes for nonclustered indexes). An nvarchar(450) column reaches the 900-byte limit (450 x 2 bytes), while a varchar(900) column reaches the same limit using single-byte characters.
- If your data is exclusively ASCII, nvarchar doubles storage compared to varchar.
If you need varchar columns:
For legacy databases or strict storage requirements, create a custom field that overrides db_type:
from django.db import models
class VarcharField(models.CharField):
def db_type(self, connection):
return f"varchar({self.max_length})"
class LegacyProduct(models.Model):
sku = VarcharField(max_length=50) # Creates varchar(50) instead of nvarchar(50)
class Meta:
managed = False # For existing tables
db_table = "LegacyProduct"
Caution
Using varchar columns risks data loss if non-ASCII characters are written. Only use this approach when you're certain the column stores ASCII-only data, or when you need to match an existing database schema.