make every grade's id its class number and sort grades by it everywhere
Grade ids were the order the books were imported in (ninth=1, eighth=5), so gradeId: 5 meant eighth grade and the admin, the question filter and the API all listed grades out of order. Grade.number (1-12) is now read from the title, new grades take it as their id, and migration 0008 moves existing ids plus every reference to them: Unit, the loose grade_id in accounts/ai_tutor/rag, and the grade target inside campaign JSON. Unnumbered demo grades move above 100 and the id sequence is raised past 12 so they never collide with a real grade. The frontend needs no change: it always reads gradeId from the server. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,10 +1,48 @@
|
||||
import re
|
||||
|
||||
from django.db import models
|
||||
|
||||
# «پایه هشتم» → ۸. فقط دوازده پایه وجود دارد، پس شمارهی پایه یک کلیدِ طبیعی و
|
||||
# پایدار است؛ id هر پایه همین شماره است (پایین، `Grade.save`).
|
||||
GRADE_NUMBERS = {
|
||||
'اول': 1, 'دوم': 2, 'سوم': 3, 'چهارم': 4, 'پنجم': 5, 'ششم': 6,
|
||||
'هفتم': 7, 'هشتم': 8, 'نهم': 9, 'دهم': 10, 'یازدهم': 11, 'دوازدهم': 12,
|
||||
}
|
||||
_GRADE_TITLE = re.compile(r'^\s*پایه[\sٔ]*(\S+)\s*$')
|
||||
|
||||
|
||||
def grade_number_from_title(title: str):
|
||||
"""«پایه نهم» → 9؛ عنوانی که دقیقاً این شکل را ندارد ([DEMO]، [SEED]، …) → None."""
|
||||
match = _GRADE_TITLE.match(title or '')
|
||||
return GRADE_NUMBERS.get(match.group(1)) if match else None
|
||||
|
||||
|
||||
class Grade(models.Model):
|
||||
title = models.CharField(max_length=50)
|
||||
icon = models.CharField(max_length=100)
|
||||
color = models.CharField(max_length=10)
|
||||
# شمارهی پایه (۱ تا ۱۲) و همزمان id آن. بدونِ این، id ترتیبِ واردشدنِ
|
||||
# کتابها بود (نهم=۱، هشتم=۵) و همهجا — ادمین، فیلترِ سوالها، API — پایهها
|
||||
# نامرتب نمایش داده میشدند.
|
||||
number = models.PositiveSmallIntegerField(
|
||||
null=True, blank=True, unique=True,
|
||||
help_text='شمارهی پایه، ۱ تا ۱۲. خالی بماند از عنوان حدس زده میشود.',
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = [models.F('number').asc(nulls_last=True), 'id']
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if self.number is None:
|
||||
guess = grade_number_from_title(self.title)
|
||||
if guess and not Grade.objects.filter(number=guess).exclude(pk=self.pk).exists():
|
||||
self.number = guess
|
||||
# پایهی تازه id را از شمارهاش میگیرد، نه از شمارندهی دیتابیس؛ وگرنه
|
||||
# «پایه چهارم» که بعداً اضافه شود id=13 میگرفت.
|
||||
if (self._state.adding and self.pk is None and self.number
|
||||
and not Grade.objects.filter(pk=self.number).exists()):
|
||||
self.pk = self.number
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
||||
Reference in New Issue
Block a user