From 4ac21100a3d01bb35d218d6b51fe5232942de404 Mon Sep 17 00:00:00 2001 From: xoliqberdiyev Date: Tue, 5 May 2026 16:32:22 +0500 Subject: [PATCH] feat: add new model for comment files --- .../0003_commentfile_remove_comment_file.py | 29 +++++++ core/apps/tasks/models/comment.py | 13 +++- core/apps/tasks/serializers/comment.py | 78 +++++++++++++++---- 3 files changed, 104 insertions(+), 16 deletions(-) create mode 100644 core/apps/tasks/migrations/0003_commentfile_remove_comment_file.py diff --git a/core/apps/tasks/migrations/0003_commentfile_remove_comment_file.py b/core/apps/tasks/migrations/0003_commentfile_remove_comment_file.py new file mode 100644 index 0000000..365dce1 --- /dev/null +++ b/core/apps/tasks/migrations/0003_commentfile_remove_comment_file.py @@ -0,0 +1,29 @@ +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tasks', '0002_alter_comment_created_by'), + ] + + operations = [ + migrations.RemoveField( + model_name='comment', + name='file', + ), + migrations.CreateModel( + name='CommentFile', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('file', models.FileField(upload_to='comments/')), + ('comment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='files', to='tasks.comment')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/core/apps/tasks/models/comment.py b/core/apps/tasks/models/comment.py index 71d6925..6b64954 100644 --- a/core/apps/tasks/models/comment.py +++ b/core/apps/tasks/models/comment.py @@ -8,9 +8,18 @@ from core.apps.tasks.choices.comment import MessageChoice class Comment(AbstractBaseModel): task = models.ForeignKey('tasks.Task', on_delete=models.CASCADE, related_name='comments') message = models.TextField() - file = models.FileField(upload_to='comments/', blank=True, null=True) type = models.CharField(max_length=255, choices=MessageChoice.choices) created_by = models.ForeignKey('accounts.User', on_delete=models.CASCADE, related_name='comments') def __str__(self): - return f"{self.content} created by {self.created_by}" + return f"{self.message} created by {self.created_by}" + + +class CommentFile(AbstractBaseModel): + comment = models.ForeignKey( + 'tasks.Comment', on_delete=models.CASCADE, related_name='files' + ) + file = models.FileField(upload_to='comments/') + + def __str__(self): + return f"File for comment {self.comment_id}" diff --git a/core/apps/tasks/serializers/comment.py b/core/apps/tasks/serializers/comment.py index 0d9202d..e860663 100644 --- a/core/apps/tasks/serializers/comment.py +++ b/core/apps/tasks/serializers/comment.py @@ -2,38 +2,88 @@ from django.db import transaction from rest_framework import serializers -from core.apps.tasks.models.comment import Comment -from core.apps.tasks.models.task import Task +from core.apps.tasks.models.comment import Comment, CommentFile + + +class CommentCreatedBySerializer(serializers.Serializer): + id = serializers.IntegerField() + first_name = serializers.CharField() + last_name = serializers.CharField() + avatar = serializers.SerializerMethodField() + + def get_avatar(self, obj): + request = self.context.get('request') + if obj.avatar and request: + return request.build_absolute_uri(obj.avatar.url) + if obj.avatar: + return obj.avatar.url + return None + + +class CommentFileSerializer(serializers.ModelSerializer): + file = serializers.SerializerMethodField() + + class Meta: + model = CommentFile + fields = ['id', 'file'] + + def get_file(self, obj): + request = self.context.get('request') + if not obj.file: + return None + if request: + return request.build_absolute_uri(obj.file.url) + return obj.file.url class CommentSerializer(serializers.ModelSerializer): + created_by = CommentCreatedBySerializer(read_only=True) + files = CommentFileSerializer(many=True, read_only=True) + class Meta: model = Comment fields = [ - 'id', 'message', 'file', 'type', 'created_by' + 'id', 'message', 'type', 'created_by', 'created_at', 'files' ] - def get_created_by(self, obj): - request = self.context.get('request') - return { - "id": obj.created_by.id, - "first_name": obj.created_by.first_name, - "last_name": obj.created_by.last_name, - "avatar": request.build_absolute_uri(obj.created_by.avatar.url) if obj.created_by.avatar else None - } - class CommentCreateSerializer(serializers.ModelSerializer): + files = serializers.ListField( + child=serializers.FileField(), + required=False, + write_only=True, + ) + class Meta: model = Comment fields = [ - 'id', 'message', 'file', 'type', 'task' + 'id', 'message', 'type', 'task', 'files', 'created_at' ] + read_only_fields = ['id', 'created_at'] def create(self, validated_data): + files = validated_data.pop('files', []) with transaction.atomic(): comment = Comment.objects.create( created_by=self.context['request'].user, **validated_data ) - return comment \ No newline at end of file + CommentFile.objects.bulk_create([ + CommentFile(comment=comment, file=f) for f in files + ]) + return comment + + def update(self, instance, validated_data): + files = validated_data.pop('files', None) + with transaction.atomic(): + for attr, value in validated_data.items(): + setattr(instance, attr, value) + instance.save() + if files is not None: + CommentFile.objects.bulk_create([ + CommentFile(comment=instance, file=f) for f in files + ]) + return instance + + def to_representation(self, instance): + return CommentSerializer(instance, context=self.context).data -- 2.49.1