Skip to content

Commit 49a5b26

Browse files
authored
refactor: perform comment soft_deletion (#99)
1 parent 40a7e25 commit 49a5b26

File tree

15 files changed

+117
-158
lines changed

15 files changed

+117
-158
lines changed

backend/apps/comment/admin.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@
77

88
@admin.register(CommentModel)
99
class CommentAdmin(admin.ModelAdmin):
10-
list_display = ('quibbler', 'content', 'created_at')
10+
list_display = ('quibbler', 'content', 'created_at', 'deleted')
1111
search_fields = ('quibbler__username', 'content')

backend/apps/comment/api/v1/urls.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
from rest_framework import routers
22

3-
from .viewsets import CommentViewSet
3+
from .viewsets import CommentModelViewSet
44

55
router = routers.DefaultRouter()
6-
router.register(r'', CommentViewSet)
6+
router.register(r'', CommentModelViewSet)
77

88
urlpatterns = router.urls

backend/apps/comment/api/v1/viewsets.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
from .serializers import CommentSerializer
55

66

7-
class CommentViewSet(viewsets.ModelViewSet):
7+
class CommentModelViewSet(viewsets.ModelViewSet):
88
queryset = CommentModel.objects.all()
99
serializer_class = CommentSerializer
10+
11+
def perform_destroy(self, instance):
12+
CommentModel.objects.soft_delete(instance) # pyright: ignore
13+
# perform cleanup
14+
CommentModel.objects.clean_up_soft_deleted() # pyright: ignore

backend/apps/comment/managers.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from django.db import models
2+
3+
4+
class CommentManager(models.Manager):
5+
def soft_delete(self, instance):
6+
# if no children- hard delete
7+
if instance.children_count == 0:
8+
instance.delete()
9+
# else- soft delete
10+
else:
11+
instance.deleted = True
12+
instance.content = "[deleted]"
13+
instance.quibbler = None
14+
instance.save()
15+
16+
def clean_up_soft_deleted(self):
17+
# cleanup all comment instances with no children
18+
for comment_instance in self.filter(deleted=True):
19+
if comment_instance.children_count == 0:
20+
comment_instance.delete()
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Generated by Django 5.1.4 on 2024-12-14 10:10
2+
3+
import django.db.models.deletion
4+
from django.db import migrations, models
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('comment', '0002_initial'),
11+
('user', '0001_initial'),
12+
]
13+
14+
operations = [
15+
migrations.AddField(
16+
model_name='commentmodel',
17+
name='deleted',
18+
field=models.BooleanField(default=False),
19+
),
20+
migrations.AlterField(
21+
model_name='commentmodel',
22+
name='quibbler',
23+
field=models.ForeignKey(
24+
null=True,
25+
on_delete=django.db.models.deletion.SET_NULL,
26+
to='user.profilemodel',
27+
verbose_name='quibbler',
28+
),
29+
),
30+
]
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Generated by Django 5.1.4 on 2024-12-14 10:51
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('comment', '0003_commentmodel_deleted_alter_commentmodel_quibbler'),
10+
('user', '0001_initial'),
11+
]
12+
13+
operations = [
14+
migrations.AlterField(
15+
model_name='commentmodel',
16+
name='downvotes',
17+
field=models.ManyToManyField(
18+
blank=True,
19+
related_name='downvoted_comments',
20+
to='user.profilemodel',
21+
verbose_name='downvotes',
22+
),
23+
),
24+
migrations.AlterField(
25+
model_name='commentmodel',
26+
name='upvotes',
27+
field=models.ManyToManyField(
28+
blank=True,
29+
related_name='upvoted_comments',
30+
to='user.profilemodel',
31+
verbose_name='upvotes',
32+
),
33+
),
34+
]

backend/apps/comment/models.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,36 @@
66
from apps.user.models import ProfileModel
77
from common.mixins.model_mixins import CreatedAtMixin
88

9+
from .managers import CommentManager
10+
911
# Create your models here.
1012

1113

1214
class CommentModel(CreatedAtMixin, TreeModel):
1315
quibbler = models.ForeignKey(
14-
ProfileModel, on_delete=models.CASCADE, verbose_name=_('quibbler')
16+
ProfileModel, on_delete=models.SET_NULL, null=True, verbose_name=_('quibbler')
1517
)
1618
content = models.TextField(_('content'))
1719
upvotes = models.ManyToManyField(
18-
ProfileModel, related_name='upvotes', blank=True, verbose_name=_('upvotes')
20+
ProfileModel, related_name='upvoted_comments', blank=True, verbose_name=_('upvotes')
1921
)
2022
downvotes = models.ManyToManyField(
21-
ProfileModel, related_name='downvotes', blank=True, verbose_name=_('downvotes')
23+
ProfileModel,
24+
related_name='downvoted_comments',
25+
blank=True,
26+
verbose_name=_('downvotes'),
2227
)
28+
# flag
29+
deleted = models.BooleanField(default=False)
30+
# custom manager for soft-deletions handling
31+
objects = CommentManager()
2332

2433
@property
2534
def children_count(self):
2635
return self.children().count()
2736

2837
def __str__(self) -> str:
29-
return f"Comment by {self.quibbler.username}"
38+
return f"Comment by {self.quibbler}"
3039

3140
class Meta: # pyright: ignore
3241
indexes = [idx.GistIndex(fields=['path'])]

backend/apps/quib/api/v1/urls.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
from rest_framework.routers import DefaultRouter
22

3-
from .viewsets import QuibViewSet
3+
from .viewsets import QuibModelViewSet
44

55
router = DefaultRouter()
6-
router.register(r'', QuibViewSet)
6+
router.register(r'', QuibModelViewSet)
77

88
urlpatterns = router.urls

backend/apps/quib/api/v1/viewsets.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from .serializers import QuibSerializer, QuibSlimSerializer
1111

1212

13-
class QuibViewSet(viewsets.ModelViewSet):
13+
class QuibModelViewSet(viewsets.ModelViewSet):
1414
queryset = QuibModel.objects.all()
1515

1616
def get_serializer_class(self): # pyright: ignore

backend/apps/quiblet/api/v1/urls.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
from rest_framework.routers import DefaultRouter
22

3-
from .viewsets import QuibletViewSet
3+
from .viewsets import QuibletModelViewSet
44

55
router = DefaultRouter()
6-
router.register(r'', QuibletViewSet)
6+
router.register(r'', QuibletModelViewSet)
77

88
urlpatterns = router.urls

backend/apps/quiblet/api/v1/viewsets.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from .serializers import QuibletSerializer
99

1010

11-
class QuibletViewSet(ModelViewSet):
11+
class QuibletModelViewSet(ModelViewSet):
1212
queryset = QuibletModel.objects.all()
1313
serializer_class = QuibletSerializer
1414

backend/apps/user/api/v1/urls.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
from rest_framework.routers import DefaultRouter
33

44
from .views import LoginAPIView, LogoutAPIView, MeAPIView, RegisterAPIView
5-
from .viewsets import MyProfilesViewSet, ProfileViewSet
5+
from .viewsets import MyProfilesModelViewSet, ProfileModelReadOnlyViewSet
66

77
router = DefaultRouter()
8-
router.register(r'profiles', ProfileViewSet)
9-
router.register(r'me/profiles', MyProfilesViewSet, basename='me-profile')
8+
router.register(r'profiles', ProfileModelReadOnlyViewSet)
9+
router.register(r'me/profiles', MyProfilesModelViewSet, basename='me-profile')
1010

1111
urlpatterns = [
1212
# auth endpoints

backend/apps/user/api/v1/viewsets.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from .serializers import ProfileSerializer
66

77

8-
class ProfileViewSet(viewsets.ReadOnlyModelViewSet):
8+
class ProfileModelReadOnlyViewSet(viewsets.ReadOnlyModelViewSet):
99
"""
1010
ViewSet for performing read-only operations on the Profile model.
1111
@@ -19,7 +19,7 @@ class ProfileViewSet(viewsets.ReadOnlyModelViewSet):
1919
search_fields = ('username',)
2020

2121

22-
class MyProfilesViewSet(viewsets.ModelViewSet):
22+
class MyProfilesModelViewSet(viewsets.ModelViewSet):
2323
"""
2424
ViewSet to manage profiles associated with the authenticated user.
2525

backend/locale/.gitkeep

Whitespace-only changes.

backend/locale/en/LC_MESSAGES/django.po

Lines changed: 0 additions & 139 deletions
This file was deleted.

0 commit comments

Comments
 (0)