Skip to content

Commit e928627

Browse files
committed
Fix #3: Add some documentation on how to migrate from django-mptt
1 parent 97c6e80 commit e928627

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-0
lines changed

CHANGELOG.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ Next version
77
- Made the new ``tree_queries.admin`` module importable when
88
``django-js-asset`` isn't installed so that ``compilemessages`` and other
99
tools automatically importing this module are allowed to work.
10+
- Added an example migration to the documentation for migrating from
11+
django-mptt to django-tree-queries. Thanks to @felixmm for providing this!
1012

1113

1214
0.21 (2025-09-16)

README.rst

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,3 +521,52 @@ The ``TreeAdmin`` provides:
521521
- ``move_column``: Provides move controls (cut, paste, move-to-root)
522522

523523
These are included by default in ``TreeAdmin.list_display``.
524+
525+
526+
Migrating from django-mptt
527+
~~~~~~~~~~~~~~~~~~~~~~~~~~~
528+
529+
When migrating from django-mptt to django-tree-queries, you'll need to populate
530+
the ``position`` field (or whatever field you use for sibling ordering) based on
531+
the existing MPTT ``lft`` values. Here's an example migration:
532+
533+
.. code-block:: python
534+
535+
def fill_position(apps, schema_editor):
536+
ModelWithMPTT = apps.get_model("your_app", "ModelWithMPTT")
537+
db_alias = schema_editor.connection.alias
538+
position_map = ModelWithMPTT.objects.using(db_alias).annotate(
539+
lft_rank=Window(
540+
expression=RowNumber(),
541+
partition_by=[F("parent_id")],
542+
order_by=["lft"],
543+
),
544+
).in_bulk()
545+
# Update batches of 2000 objects.
546+
batch_size = 2000
547+
qs = ModelWithMPTT.objects.all()
548+
batches = (qs[i : i + batch_size] for i in range(0, qs.count(), batch_size))
549+
for batch in batches:
550+
for obj in batch:
551+
obj.position = position_map[obj.pk].lft_rank
552+
ModelWithMPTT.objects.bulk_update(batch, ["position"])
553+
554+
class Migration(migrations.Migration):
555+
556+
dependencies = [...]
557+
558+
operations = [
559+
migrations.RunPython(
560+
code=fill_position,
561+
reverse_code=migrations.RunPython.noop,
562+
)
563+
]
564+
565+
This migration uses Django's ``Window`` function with ``RowNumber()`` to assign
566+
position values based on the original MPTT ``lft`` ordering, ensuring that siblings
567+
maintain their relative order after the migration.
568+
569+
Note that the position field is used purely for ordering siblings and is not an
570+
index. By default, django-tree-queries' admin interface starts with a position
571+
value of 10 and increments by 10 (10, 20, 30, etc.) to make it clear that the
572+
value is not an index, but just something to order siblings by.

0 commit comments

Comments
 (0)