Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80d2ee68bc | ||
|
|
fdfd238044 | ||
|
|
c4a0195aa9 | ||
|
|
92164a65c5 | ||
|
|
873c1d7085 |
@@ -28,6 +28,7 @@ class PageSerializer(BaseSerializer):
|
||||
# Many to many
|
||||
label_ids = serializers.ListField(child=serializers.UUIDField(), required=False)
|
||||
project_ids = serializers.ListField(child=serializers.UUIDField(), required=False)
|
||||
sort_order = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = Page
|
||||
@@ -51,6 +52,7 @@ class PageSerializer(BaseSerializer):
|
||||
"logo_props",
|
||||
"label_ids",
|
||||
"project_ids",
|
||||
"sort_order",
|
||||
]
|
||||
read_only_fields = ["workspace", "owned_by"]
|
||||
|
||||
@@ -121,6 +123,14 @@ class PageSerializer(BaseSerializer):
|
||||
|
||||
return super().update(instance, validated_data)
|
||||
|
||||
def get_sort_order(self, obj):
|
||||
"""Get sort_order from prefetched ProjectPage for the specific project"""
|
||||
if hasattr(obj, "current_project_page") and obj.current_project_page:
|
||||
return obj.current_project_page[0].sort_order
|
||||
|
||||
# If project_id is not available, return default sort_order
|
||||
return Page.DEFAULT_SORT_ORDER
|
||||
|
||||
|
||||
class PageDetailSerializer(PageSerializer):
|
||||
description_html = serializers.CharField()
|
||||
|
||||
@@ -15,6 +15,7 @@ from django.db.models import (
|
||||
Case,
|
||||
When,
|
||||
IntegerField,
|
||||
Prefetch,
|
||||
)
|
||||
from django.http import StreamingHttpResponse
|
||||
from django.contrib.postgres.aggregates import ArrayAgg
|
||||
@@ -98,6 +99,15 @@ class PageViewSet(BaseViewSet):
|
||||
.annotate(is_favorite=Exists(subquery))
|
||||
.order_by(self.request.GET.get("order_by", "-created_at"))
|
||||
.prefetch_related("labels")
|
||||
.prefetch_related(
|
||||
Prefetch(
|
||||
"project_pages",
|
||||
queryset=ProjectPage.objects.filter(
|
||||
project_id=self.kwargs.get("project_id"), deleted_at__isnull=True
|
||||
),
|
||||
to_attr="current_project_page",
|
||||
)
|
||||
)
|
||||
.order_by("-is_favorite", "-created_at")
|
||||
.annotate(
|
||||
project=Exists(
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
|
||||
# Generated by Django 4.2.22 on 2025-12-15 09:34
|
||||
from typing import Any
|
||||
|
||||
|
||||
from django.db import migrations, models
|
||||
from django.db.models import Count, Max
|
||||
|
||||
|
||||
def set_page_sort_order(apps, schema_editor):
|
||||
Page = apps.get_model("db", "Page")
|
||||
|
||||
DEFAULT = 65535
|
||||
BATCH_SIZE = 3000
|
||||
INCREMENT_VALUE = 10000
|
||||
|
||||
ProjectPage = apps.get_model("db", "ProjectPage")
|
||||
|
||||
# move all the parent id sort order to their project page model.
|
||||
project_pages = ProjectPage.objects.filter(page__parent_id__isnull=False).select_related("page")
|
||||
project_pages_to_update = []
|
||||
for project_page in project_pages.iterator(chunk_size=BATCH_SIZE):
|
||||
project_page.sort_order = project_page.page.sort_order
|
||||
project_pages_to_update.append(project_page)
|
||||
if len(project_pages_to_update) >= BATCH_SIZE:
|
||||
ProjectPage.objects.bulk_update(project_pages_to_update, ["sort_order"], batch_size=BATCH_SIZE)
|
||||
project_pages_to_update = []
|
||||
|
||||
# Update remaining items
|
||||
if project_pages_to_update:
|
||||
ProjectPage.objects.bulk_update(project_pages_to_update, ["sort_order"], batch_size=BATCH_SIZE)
|
||||
|
||||
# Step 1: Find workspaces with duplicate DEFAULT_SORT_ORDER pages
|
||||
workspace_ids = (
|
||||
Page.objects
|
||||
.filter(sort_order=DEFAULT)
|
||||
.values("workspace_id")
|
||||
.annotate(cnt=Count("id"))
|
||||
.filter(cnt__gt=1)
|
||||
.values_list("workspace_id", flat=True)
|
||||
)
|
||||
|
||||
for workspace_id in workspace_ids.iterator(chunk_size=500):
|
||||
# Step 2: get max sort_order in the workspace
|
||||
max_sort = (
|
||||
Page.objects
|
||||
.filter(workspace_id=workspace_id)
|
||||
.aggregate(m=Max("sort_order"))["m"] or 0
|
||||
)
|
||||
|
||||
# Step 3: fetch duplicate pages
|
||||
pages = list[Any](
|
||||
Page.objects
|
||||
.filter(workspace_id=workspace_id, sort_order=DEFAULT)
|
||||
.only("id", "sort_order")
|
||||
)
|
||||
|
||||
|
||||
# Step 4: assign unique increasing sort orders
|
||||
next_sort = max_sort + INCREMENT_VALUE
|
||||
for page in pages:
|
||||
page.sort_order = next_sort
|
||||
next_sort += INCREMENT_VALUE
|
||||
|
||||
Page.objects.bulk_update(pages, ["sort_order"], batch_size=BATCH_SIZE)
|
||||
|
||||
|
||||
def reverse_set_page_sort_order(apps, schema_editor):
|
||||
ProjectPage = apps.get_model("db", "ProjectPage")
|
||||
DEFAULT_SORT_ORDER = 65535
|
||||
ProjectPage.objects.update(sort_order=DEFAULT_SORT_ORDER)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('db', '0112_auto_20251124_0603'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='projectpage',
|
||||
name='sort_order',
|
||||
field=models.FloatField(default=65535),
|
||||
),
|
||||
migrations.RunPython(
|
||||
set_page_sort_order, reverse_code=reverse_set_page_sort_order
|
||||
),
|
||||
]
|
||||
@@ -132,6 +132,7 @@ class ProjectPage(BaseModel):
|
||||
project = models.ForeignKey("db.Project", on_delete=models.CASCADE, related_name="project_pages")
|
||||
page = models.ForeignKey("db.Page", on_delete=models.CASCADE, related_name="project_pages")
|
||||
workspace = models.ForeignKey("db.Workspace", on_delete=models.CASCADE, related_name="project_pages")
|
||||
sort_order = models.FloatField(default=Page.DEFAULT_SORT_ORDER)
|
||||
|
||||
class Meta:
|
||||
unique_together = ["project", "page", "deleted_at"]
|
||||
@@ -149,6 +150,22 @@ class ProjectPage(BaseModel):
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.project.name} {self.page.name}"
|
||||
|
||||
def _set_sort_for_root_page(self):
|
||||
"""
|
||||
Set sort_order for project pages when the associated page has no parent in the workspace.
|
||||
"""
|
||||
largest_sort_order = ProjectPage.objects.filter(project=self.project).aggregate(
|
||||
largest=models.Max("sort_order")
|
||||
)["largest"]
|
||||
|
||||
if largest_sort_order is not None:
|
||||
self.sort_order = largest_sort_order + 10000
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if self._state.adding:
|
||||
self._set_sort_for_root_page()
|
||||
super(ProjectPage, self).save(*args, **kwargs)
|
||||
|
||||
|
||||
class PageVersion(BaseModel):
|
||||
|
||||
Reference in New Issue
Block a user