AffinityRule / AffinityLevel / AffinitySetting 三表共 13 条 CheckConstraint 覆盖 min ≤ max / 各类 cap > 0 / cooldown ≥ 0 / companion_time 配套字段必填 / decay 区间合法 / initial ≤ max 等不变量。 AffinitySetting 加 pk=1 单例硬约束(CR-002 + WR-001 联动)+ save() 强制 pk=1, 形成事实单例防御并发首次插入重复行。 模型 clean() 提供 Python 级兜底(给 DRF / admin 友好错误信息); AffinityLevel.save() 自动 full_clean 触发跨行区间不重叠校验(为 WR-009 铺路)。 详见 docs/REVIEW-affinity-P1.md CR-002 / WR-001。
66 lines
3.3 KiB
Python
66 lines
3.3 KiB
Python
# Generated by Django 5.2.12 on 2026-05-13 02:11
|
|
|
|
from django.db import migrations, models
|
|
|
|
|
|
class Migration(migrations.Migration):
|
|
|
|
dependencies = [
|
|
('userapp', '0006_migrate_favorability_to_userdevice'),
|
|
]
|
|
|
|
operations = [
|
|
migrations.AddConstraint(
|
|
model_name='affinitylevel',
|
|
constraint=models.CheckConstraint(condition=models.Q(('min_affinity__lte', models.F('max_affinity'))), name='affinitylevel_min_le_max'),
|
|
),
|
|
migrations.AddConstraint(
|
|
model_name='affinitylevel',
|
|
constraint=models.CheckConstraint(condition=models.Q(('reward_currency__gte', 0)), name='affinitylevel_currency_nonneg'),
|
|
),
|
|
migrations.AddConstraint(
|
|
model_name='affinityrule',
|
|
constraint=models.CheckConstraint(condition=models.Q(('min_change__lte', models.F('max_change'))), name='affinityrule_min_le_max'),
|
|
),
|
|
migrations.AddConstraint(
|
|
model_name='affinityrule',
|
|
constraint=models.CheckConstraint(condition=models.Q(('cooldown_seconds__gte', 0)), name='affinityrule_cooldown_nonneg'),
|
|
),
|
|
migrations.AddConstraint(
|
|
model_name='affinityrule',
|
|
constraint=models.CheckConstraint(condition=models.Q(('single_cap__gt', 0)), name='affinityrule_single_cap_positive'),
|
|
),
|
|
migrations.AddConstraint(
|
|
model_name='affinityrule',
|
|
constraint=models.CheckConstraint(condition=models.Q(('daily_cap__gt', 0)), name='affinityrule_daily_cap_positive'),
|
|
),
|
|
migrations.AddConstraint(
|
|
model_name='affinityrule',
|
|
constraint=models.CheckConstraint(condition=models.Q(models.Q(('trigger_type', 'companion_time'), _negated=True), models.Q(('min_continuous_minutes__gt', 0), ('max_count_per_day__gt', 0)), _connector='OR'), name='affinityrule_companion_fields_present'),
|
|
),
|
|
migrations.AddConstraint(
|
|
model_name='affinitysetting',
|
|
constraint=models.CheckConstraint(condition=models.Q(('decay_min_decay__lte', models.F('decay_max_decay'))), name='affinitysetting_decay_min_le_max'),
|
|
),
|
|
migrations.AddConstraint(
|
|
model_name='affinitysetting',
|
|
constraint=models.CheckConstraint(condition=models.Q(('decay_max_decay__lte', models.F('decay_cap'))), name='affinitysetting_decay_within_cap'),
|
|
),
|
|
migrations.AddConstraint(
|
|
model_name='affinitysetting',
|
|
constraint=models.CheckConstraint(condition=models.Q(('initial_affinity__lte', models.F('max_affinity'))), name='affinitysetting_initial_le_max'),
|
|
),
|
|
migrations.AddConstraint(
|
|
model_name='affinitysetting',
|
|
constraint=models.CheckConstraint(condition=models.Q(('decay_min_floor__lte', models.F('max_affinity'))), name='affinitysetting_floor_le_max'),
|
|
),
|
|
migrations.AddConstraint(
|
|
model_name='affinitysetting',
|
|
constraint=models.CheckConstraint(condition=models.Q(('daily_cap__gt', 0)), name='affinitysetting_daily_cap_positive'),
|
|
),
|
|
migrations.AddConstraint(
|
|
model_name='affinitysetting',
|
|
constraint=models.CheckConstraint(condition=models.Q(('pk', 1)), name='affinitysetting_singleton'),
|
|
),
|
|
]
|