feat(reaction): 新增 reaction app 与数据模型
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -55,6 +55,7 @@ LOCAL_APPS = [
|
|||||||
"judge",
|
"judge",
|
||||||
"message",
|
"message",
|
||||||
"comment",
|
"comment",
|
||||||
|
"reaction",
|
||||||
"tutorial",
|
"tutorial",
|
||||||
"ai",
|
"ai",
|
||||||
"flowchart",
|
"flowchart",
|
||||||
|
|||||||
0
reaction/__init__.py
Normal file
0
reaction/__init__.py
Normal file
33
reaction/migrations/0001_initial.py
Normal file
33
reaction/migrations/0001_initial.py
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Generated by Django 6.0.4 on 2026-08-06 07:35
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('problem', '0014_problem_tag_ci_unique'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Reaction',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('type', models.CharField(choices=[('too_easy', '太简单'), ('too_hard', '太难了'), ('confusing', '没看懂'), ('buggy', '题目有错'), ('learned', '学到了'), ('interesting', '有意思'), ('want_explain', '想听讲解')], max_length=20, verbose_name='表情类型')),
|
||||||
|
('create_time', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('problem', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='problem.problem')),
|
||||||
|
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'db_table': 'reaction',
|
||||||
|
'indexes': [models.Index(fields=['problem', 'type'], name='reaction_problem_type_idx')],
|
||||||
|
'unique_together': {('problem', 'user', 'type')},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
0
reaction/migrations/__init__.py
Normal file
0
reaction/migrations/__init__.py
Normal file
28
reaction/models.py
Normal file
28
reaction/models.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
from django.db import models
|
||||||
|
|
||||||
|
from account.models import User
|
||||||
|
from problem.models import Problem
|
||||||
|
|
||||||
|
|
||||||
|
class ReactionType(models.TextChoices):
|
||||||
|
TOO_EASY = "too_easy", "太简单"
|
||||||
|
TOO_HARD = "too_hard", "太难了"
|
||||||
|
CONFUSING = "confusing", "没看懂"
|
||||||
|
BUGGY = "buggy", "题目有错"
|
||||||
|
LEARNED = "learned", "学到了"
|
||||||
|
INTERESTING = "interesting", "有意思"
|
||||||
|
WANT_EXPLAIN = "want_explain", "想听讲解"
|
||||||
|
|
||||||
|
|
||||||
|
class Reaction(models.Model):
|
||||||
|
problem = models.ForeignKey(Problem, on_delete=models.CASCADE)
|
||||||
|
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||||
|
type = models.CharField(max_length=20, choices=ReactionType.choices, verbose_name="表情类型")
|
||||||
|
create_time = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
db_table = "reaction"
|
||||||
|
unique_together = ("problem", "user", "type")
|
||||||
|
indexes = [
|
||||||
|
models.Index(fields=["problem", "type"], name="reaction_problem_type_idx"),
|
||||||
|
]
|
||||||
18
reaction/serializers.py
Normal file
18
reaction/serializers.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from reaction.models import ReactionType
|
||||||
|
from utils.api import serializers
|
||||||
|
|
||||||
|
MAX_REACTIONS = 3
|
||||||
|
|
||||||
|
|
||||||
|
class SetReactionSerializer(serializers.Serializer):
|
||||||
|
problem_id = serializers.IntegerField()
|
||||||
|
types = serializers.ListField(
|
||||||
|
child=serializers.ChoiceField(choices=ReactionType.choices),
|
||||||
|
allow_empty=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
def validate_types(self, value):
|
||||||
|
unique = list(dict.fromkeys(value))
|
||||||
|
if len(unique) > MAX_REACTIONS:
|
||||||
|
raise serializers.ValidationError(f"最多只能选 {MAX_REACTIONS} 个")
|
||||||
|
return unique
|
||||||
0
reaction/urls/__init__.py
Normal file
0
reaction/urls/__init__.py
Normal file
0
reaction/views/__init__.py
Normal file
0
reaction/views/__init__.py
Normal file
@@ -18,6 +18,7 @@ class CacheKey:
|
|||||||
problem_authors = "problem_authors"
|
problem_authors = "problem_authors"
|
||||||
problem_tags = "problem_tags"
|
problem_tags = "problem_tags"
|
||||||
comment_stats = "comment_stats"
|
comment_stats = "comment_stats"
|
||||||
|
reaction_stats = "reaction_stats"
|
||||||
user_activity_rank = "user_activity_rank"
|
user_activity_rank = "user_activity_rank"
|
||||||
problem_yearly_ac = "problem_yearly_ac"
|
problem_yearly_ac = "problem_yearly_ac"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user