Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,22 @@ Changelog
1.1
===

1.1.3
-----

Added
^^^^^
- ``RandomHex`` dialect-aware ``SqlDefault`` subclass for generating random hex strings across all backends. (#2108)
- ``Meta.constraints`` support on models — named ``UniqueConstraint`` objects are now captured by the migration autodetector, enabling ``AddConstraint``/``RemoveConstraint`` generation via ``makemigrations``. (#2108)
- MySQL schema editor: ``_alter_field`` override using ``MODIFY COLUMN`` for NULL/NOT NULL changes; backtick-quoted ``ALTER_FIELD_*`` templates. (#2108)
- MSSQL schema editor: ``_alter_field`` override with ``ALTER COLUMN`` for nullability, named default constraint management via ``sys.default_constraints``, bracket-quoted templates, and self-referencing FK CASCADE → NO ACTION downgrade. (#2108)

Fixed
^^^^^
- MySQL migrations: ``ALTER COLUMN ... SET NOT NULL`` / ``DROP NOT NULL`` now correctly emits ``MODIFY COLUMN col type NOT NULL/NULL``. (#2108)
- MSSQL migrations: ``DELETE_CONSTRAINT_TEMPLATE`` and ``UNIQUE_CONSTRAINT_CREATE_TEMPLATE`` now use bracket quoting ``[name]`` instead of double quotes. (#2108)
- MSSQL migrations: self-referencing foreign keys with ``CASCADE`` no longer fail with error 1785; automatically downgraded to ``NO ACTION``. (#2108)

1.1.2
-----

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@
from tortoise import migrations
from tortoise.migrations import operations as ops

_CONCAT_SQL = {
"postgres": "UPDATE employee SET full_name = first_name || ' ' || last_name WHERE full_name IS NULL",
"sqlite": "UPDATE employee SET full_name = first_name || ' ' || last_name WHERE full_name IS NULL",
"mysql": "UPDATE employee SET full_name = CONCAT(first_name, ' ', last_name) WHERE full_name IS NULL",
"mssql": "UPDATE employee SET full_name = first_name + ' ' + last_name WHERE full_name IS NULL",
}


def populate_total_amount(apps, schema_editor):
"""Convert total_cents to total_amount (cents to dollars)."""
Expand All @@ -30,6 +37,25 @@ async def do_clear():
return do_clear()


def populate_full_name(apps, schema_editor):
"""Populate full_name from first_name + last_name using dialect-specific SQL."""
sql = _CONCAT_SQL[schema_editor.DIALECT]

async def do_populate():
await schema_editor.client.execute_query(sql)

return do_populate()


def clear_full_name(apps, schema_editor):
"""Reverse: Clear full_name field."""

async def do_clear():
await schema_editor.client.execute_query("UPDATE employee SET full_name = NULL")

return do_clear()


class Migration(migrations.Migration):
dependencies = [("erp", "0010_add_computed_fields")]

Expand All @@ -40,8 +66,8 @@ class Migration(migrations.Migration):
code=populate_total_amount,
reverse_code=clear_total_amount,
),
ops.RunSQL(
sql="UPDATE employee SET full_name = first_name || ' ' || last_name WHERE full_name IS NULL",
reverse_sql="UPDATE employee SET full_name = NULL",
ops.RunPython(
code=populate_full_name,
reverse_code=clear_full_name,
),
]
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,28 @@ class Migration(migrations.Migration):
initial = False

operations = [
ops.CreateModel(
name="Warehouse",
fields=[
(
"id",
fields.IntField(generated=True, primary_key=True, unique=True, db_index=True),
),
("name", fields.CharField(max_length=200)),
("location", fields.CharField(max_length=300)),
(
"is_active",
fields.BooleanField(default=True, generated=False, null=False, unique=False),
),
],
options={
"table": "warehouse",
"app": "erp",
"pk_attr": "id",
"table_description": "Warehouse entity - storage location for inventory.",
},
bases=["Model"],
),
ops.CreateModel(
name="Alert",
fields=[
Expand Down Expand Up @@ -42,26 +64,4 @@ class Migration(migrations.Migration):
},
bases=["Model"],
),
ops.CreateModel(
name="Warehouse",
fields=[
(
"id",
fields.IntField(generated=True, primary_key=True, unique=True, db_index=True),
),
("name", fields.CharField(max_length=200)),
("location", fields.CharField(max_length=300)),
(
"is_active",
fields.BooleanField(default=True, generated=False, null=False, unique=False),
),
],
options={
"table": "warehouse",
"app": "erp",
"pk_attr": "id",
"table_description": "Warehouse entity - storage location for inventory.",
},
bases=["Model"],
),
]
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from tortoise import fields, migrations
from tortoise.fields.db_defaults import Now, SqlDefault
from tortoise.fields.db_defaults import Now, RandomHex
from tortoise.migrations import operations as ops


Expand All @@ -17,8 +17,6 @@ class Migration(migrations.Migration):
ops.AddField(
model_name="Product",
name="tracking_id",
field=fields.CharField(
null=True, db_default=SqlDefault("(lower(hex(randomblob(16))))"), max_length=36
),
field=fields.CharField(null=True, db_default=RandomHex(), max_length=36),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from tortoise import migrations
from tortoise.migrations import operations as ops
from tortoise.migrations.constraints import UniqueConstraint


class Migration(migrations.Migration):
dependencies = [("erp", "0021_add_sql_default_expressions")]

initial = False

operations = [
ops.AddConstraint(
model_name="Employee",
constraint=UniqueConstraint(fields=("first_name", "last_name"), name=None),
),
ops.AddConstraint(
model_name="Employee",
constraint=UniqueConstraint(
fields=("email", "department_id"), name="uq_employee_email_dept"
),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from tortoise import migrations
from tortoise.migrations import operations as ops


class Migration(migrations.Migration):
dependencies = [("erp", "0022_add_employee_constraints")]

initial = False

operations = [
ops.RemoveConstraint(
model_name="Employee",
name=None,
fields=["first_name", "last_name"],
),
ops.RemoveConstraint(
model_name="Employee",
name="uq_employee_email_dept",
fields=None,
),
]
4 changes: 2 additions & 2 deletions examples/comprehensive_migrations_project/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from enum import Enum, IntEnum

from tortoise import fields, models
from tortoise.fields import Now, SqlDefault
from tortoise.fields import Now, RandomHex


class OrderStatus(IntEnum):
Expand Down Expand Up @@ -121,7 +121,7 @@ class Product(models.Model):
tracking_id = fields.CharField(
max_length=36,
null=True,
db_default=SqlDefault("(lower(hex(randomblob(16))))"),
db_default=RandomHex(),
)
created_at = fields.DatetimeField(db_default=Now())

Expand Down
Loading