mod: модели и админка (6) драфт

This commit is contained in:
2026-08-20 16:35:42 +03:00
parent 99c317431e
commit eff510eb4b
2 changed files with 34 additions and 8 deletions
+4
View File
@@ -206,6 +206,10 @@ LVL_PRE_MODERATED = 10
LVL_MODERATED = 30
LVL_LOCK_FOR_DELETION = 1000
# ====== Направление и веса для голосования (ТОЛЛЬКО ЦЕЛЫЕ ЧИСЛА) ======
VOTE_LIKE = 1
VOTE_CLAIM = -2
# ====== Гамма для вычисления рейтинга ======
GAMMA = 1.5
+30 -8
View File
@@ -21,6 +21,7 @@ class TbHypn0Item(models.Model):
• f_score: оценка для стратегии хранения и умной очистки (Smart Retention)
• i_level: уровень хранения (свежее, модерированное, защищенное от удаления)
• is_public: публичный (доступный по внешней ссылке)
• s_author_fingerprint: хеш-код браузера автора
• s_promo_url: промо-ссылка (с дополнительной об авторе-спонсоре)
• s_promo_title: заголовок промо-ссылки или бейджа
• i_promo_clicks: количество кликов по промо-ссылке
@@ -105,6 +106,14 @@ class TbHypn0Item(models.Model):
verbose_name="Публичный доступ",
)
# Автор
s_author_fingerprint = models.CharField(
max_length=64,
db_index=True, # ??? -- подумать нужно или нет
help_text="SHA256(visitor_uuid + SECRET_KEY) для защиты от накрутки и разделения устройств",
verbose_name="Хэш устройства/отпечаток",
)
# Промо-блок (на перспективу)
s_promo_url = models.URLField(
blank=True,
@@ -143,19 +152,21 @@ class TbHypn0Item(models.Model):
def increment_views(self):
"""Безопасный инкремент просмотров"""
TbHypn0Item.objects.filter(id=self.id).update(i_views_count=F('i_views_count') + 1)
TbHypn0Item.objects.get(id=self.id).update(i_views_count=F('i_views_count') + 1)
def increment_likes(self):
"""Безопасный инкремент лайков"""
TbHypn0Item.objects.filter(id=self.id).update(i_likes_count=F('i_likes_count') + 1)
TbHypn0Item.objects.get(id=self.id).update(i_likes_count=F('i_likes_count') + 1)
# Здесь будет код для записи в TbVote
def increment_claims(self):
"""Безопасный инкремент жалоб"""
TbHypn0Item.objects.filter(id=self.id).update(i_claims_count=F('i_claims_count') + 1)
TbHypn0Item.objects.get(id=self.id).update(i_claims_count=F('i_claims_count') + 1)
# Здесь будет код для записи в TbVote
def increment_promo_clicks(self):
"""Безопасный инкремент кликов по промо"""
TbHypn0Item.objects.filter(id=self.id).update(i_promo_clicks=F('i_promo_clicks') + 1)
TbHypn0Item.objects.get(id=self.id).update(i_promo_clicks=F('i_promo_clicks') + 1)
def rescore(self):
"""Пересчет рейтинга i_promo_clicks
@@ -163,9 +174,9 @@ class TbHypn0Item(models.Model):
(«гравитации»), а не слепой Х-дневный таймер:
$$\text{Score} = \frac{\text{Likes} + \text{Bonus}_{\text{moderator}}}{(\text{Age in hours} + 2)^\gamma}$$
"""
age_ih_hours = (timezone.now - self.d_created_at).total_seconds() / 3600 + 1
age_ih_hours = (timezone.now() - self.d_created_at).total_seconds() / 3600 + 1
new_score = (self.i_likes_count + self.i_level) / ((age_ih_hours + 2) ** GAMMA)
TbHypn0Item.objects.filter(id=self.id).update(i_promo_clicks=new_score)
TbHypn0Item.objects.get(id=self.id).update(f_score=new_score)
def save(self, *args, **kwargs):
"""
@@ -205,19 +216,30 @@ class TbVote(models.Model):
Поля:
• k_item: ключ объекта (foreign key), за который голосуют
• i_direction: направление голоса
• s_fingerprint: Хэш-отпечаток клиент/браузер/secret для защиты он накрутки
• d_created_at: дата создания
"""
class Direction(models.IntegerChoices):
LIKE = VOTE_LIKE, 'Like'
CLIME = VOTE_CLAIM, 'Clime'
k_item = models.ForeignKey(
TbHypn0Item,
on_delete=models.CASCADE,
related_name="votes",
verbose_name="Картина",
)
i_direction = models.IntegerField(
choices=Direction.choices,
default=Direction.LIKE,
verbose_name="Направление",
help_text="Направление голоса",
)
s_fingerprint = models.CharField(
max_length=64,
db_index=True,
db_index=True, # ??? -- подумать нужно или нет
help_text="SHA256(visitor_uuid + SECRET_KEY) для защиты от накрутки и разделения устройств",
verbose_name="Хэш устройства/отпечаток",
)
@@ -238,7 +260,7 @@ class TbVote(models.Model):
ordering = ["-d_created_at"]
def __str__(self) -> str:
return f"Голос за {self.k_item.hash_id} [{self.s_fingerprint[:8]}...]"
return f"Голос за {self.k_item.s_hash_id} [{self.s_fingerprint[:8]}...]"
class TbBlogPost(models.Model):