Skip to content

Commit

Permalink
feat: comment model in Ltree structure (#96)
Browse files Browse the repository at this point in the history
  • Loading branch information
moonlitgrace authored Dec 13, 2024
1 parent bc7f8d7 commit 164ec9b
Show file tree
Hide file tree
Showing 29 changed files with 460 additions and 198 deletions.
Empty file.
11 changes: 11 additions & 0 deletions backend/apps/comment/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from django.contrib import admin

from .models import Comment

# Register your models here.


@admin.register(Comment)
class CommentAdmin(admin.ModelAdmin):
list_display = ('quibbler', 'content', 'created_at')
search_fields = ('quibbler__username', 'content')
Empty file.
Empty file.
30 changes: 30 additions & 0 deletions backend/apps/comment/api/v1/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from django.shortcuts import get_object_or_404
from rest_framework import serializers

from ...models import Comment


class CommentSerializer(serializers.ModelSerializer):
path = serializers.CharField(required=False)

class Meta:
model = Comment
fields = '__all__'

def create(self, validated_data):
data = {
'quibbler': validated_data.get('quibbler')
or self.context['request'].user_profile,
'content': validated_data['content'],
}

if path := validated_data.get('path'):
parent_instance = get_object_or_404(Comment, path__match=path)
comment_instance: Comment = Comment.objects.create_child(
parent=parent_instance, **data
)
else:
comment_instance: Comment = Comment.objects.create_child(**data)

comment_instance.save()
return comment_instance
8 changes: 8 additions & 0 deletions backend/apps/comment/api/v1/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from rest_framework import routers

from .viewsets import CommentViewSet

router = routers.DefaultRouter()
router.register(r'', CommentViewSet)

urlpatterns = router.urls
9 changes: 9 additions & 0 deletions backend/apps/comment/api/v1/viewsets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from rest_framework import viewsets

from ...models import Comment
from .serializers import CommentSerializer


class CommentViewSet(viewsets.ModelViewSet):
queryset = Comment.objects.all()
serializer_class = CommentSerializer
6 changes: 6 additions & 0 deletions backend/apps/comment/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class CommentConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'apps.comment'
38 changes: 38 additions & 0 deletions backend/apps/comment/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Generated by Django 5.1.4 on 2024-12-13 12:02

import django_ltree.fields
from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = []

operations = [
migrations.CreateModel(
name='Comment',
fields=[
(
'id',
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name='ID',
),
),
('path', django_ltree.fields.PathField(unique=True)),
(
'created_at',
models.DateTimeField(auto_now_add=True, verbose_name='create at'),
),
('content', models.TextField(verbose_name='content')),
],
options={
'verbose_name': 'Comment',
'verbose_name_plural': 'Comments',
},
),
]
53 changes: 53 additions & 0 deletions backend/apps/comment/migrations/0002_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Generated by Django 5.1.4 on 2024-12-13 12:02

import django.contrib.postgres.indexes
import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = [
('comment', '0001_initial'),
('user', '0001_initial'),
]

operations = [
migrations.AddField(
model_name='comment',
name='downvotes',
field=models.ManyToManyField(
blank=True,
related_name='downvotes',
to='user.profile',
verbose_name='downvotes',
),
),
migrations.AddField(
model_name='comment',
name='quibbler',
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to='user.profile',
verbose_name='quibbler',
),
),
migrations.AddField(
model_name='comment',
name='upvotes',
field=models.ManyToManyField(
blank=True,
related_name='upvotes',
to='user.profile',
verbose_name='upvotes',
),
),
migrations.AddIndex(
model_name='comment',
index=django.contrib.postgres.indexes.GistIndex(
fields=['path'], name='comment_com_path_d1388c_gist'
),
),
]
Empty file.
34 changes: 34 additions & 0 deletions backend/apps/comment/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from django.contrib.postgres import indexes as idx
from django.db import models
from django.utils.translation import gettext_lazy as _
from django_ltree.models import TreeModel

from apps.user.models import Profile
from common.mixins.model_mixins import CreatedAtMixin

# Create your models here.


class Comment(CreatedAtMixin, TreeModel):
quibbler = models.ForeignKey(
Profile, on_delete=models.CASCADE, verbose_name=_('quibbler')
)
content = models.TextField(_('content'))
upvotes = models.ManyToManyField(
Profile, related_name='upvotes', blank=True, verbose_name=_('upvotes')
)
downvotes = models.ManyToManyField(
Profile, related_name='downvotes', blank=True, verbose_name=_('downvotes')
)

@property
def children_count(self):
return self.children().count()

def __str__(self) -> str:
return f"Comment by {self.quibbler.username}"

class Meta: # pyright: ignore
indexes = [idx.GistIndex(fields=['path'])]
verbose_name = 'Comment'
verbose_name_plural = 'Comments'
16 changes: 16 additions & 0 deletions backend/apps/quiblet/api/v1/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,23 @@ def validate_name(self, name):
return name


class QuibletSlimSerializer(ModelSerializer):
class Meta:
model = Quiblet
fields = ('name', 'avatar')


class QuibSerializer(ModelSerializer):
quiblet = QuibletSerializer(read_only=True)

class Meta:
model = Quib
fields = '__all__'


class QuibSlimSerializer(ModelSerializer):
quiblet = QuibletSlimSerializer(read_only=True)

class Meta:
model = Quib
exclude = ('quibber',)
8 changes: 6 additions & 2 deletions backend/apps/quiblet/api/v1/viewsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from common.patches.request import PatchedHttpRequest

from ...models import Quib, Quiblet
from .serializers import QuibletSerializer, QuibSerializer
from .serializers import QuibletSerializer, QuibSerializer, QuibSlimSerializer


@extend_schema(tags=['quibs & quiblets'])
Expand All @@ -28,4 +28,8 @@ def perform_create(self, serializer):
@extend_schema(tags=['quibs & quiblets'])
class QuibViewSet(ModelViewSet):
queryset = Quib.objects.all()
serializer_class = QuibSerializer

def get_serializer_class(self): # pyright: ignore
if self.action == 'list':
return QuibSlimSerializer
return QuibSerializer
98 changes: 60 additions & 38 deletions backend/apps/quiblet/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 5.1.4 on 2024-12-11 05:30
# Generated by Django 5.1.4 on 2024-12-13 12:02

import dynamic_filenames
import shortuuid.django_fields
Expand All @@ -9,45 +9,11 @@ class Migration(migrations.Migration):

initial = True

dependencies = []
dependencies = [
('comment', '0001_initial'),
]

operations = [
migrations.CreateModel(
name='Quib',
fields=[
(
'created_at',
models.DateTimeField(auto_now_add=True, verbose_name='create at'),
),
('is_public', models.BooleanField(default=True, verbose_name='is public')),
(
'id',
shortuuid.django_fields.ShortUUIDField(
alphabet='abcdefghijklmnopqrstuvwxyz0123456789',
editable=False,
length=7,
max_length=7,
prefix='',
primary_key=True,
serialize=False,
verbose_name='id',
),
),
('title', models.CharField(max_length=255, verbose_name='title')),
(
'slug',
models.SlugField(
blank=True, editable=False, max_length=25, verbose_name='slug'
),
),
('content', models.TextField(verbose_name='content')),
],
options={
'verbose_name': 'Quib',
'verbose_name_plural': 'Quibs',
'ordering': ['-created_at'],
},
),
migrations.CreateModel(
name='Quiblet',
fields=[
Expand Down Expand Up @@ -96,4 +62,60 @@ class Migration(migrations.Migration):
'ordering': ['-created_at'],
},
),
migrations.CreateModel(
name='Quib',
fields=[
(
'created_at',
models.DateTimeField(auto_now_add=True, verbose_name='create at'),
),
('is_public', models.BooleanField(default=True, verbose_name='is public')),
(
'id',
shortuuid.django_fields.ShortUUIDField(
alphabet='abcdefghijklmnopqrstuvwxyz0123456789',
editable=False,
length=7,
max_length=7,
prefix='',
primary_key=True,
serialize=False,
verbose_name='id',
),
),
('title', models.CharField(max_length=255, verbose_name='title')),
(
'slug',
models.SlugField(
blank=True, editable=False, max_length=25, verbose_name='slug'
),
),
('content', models.TextField(verbose_name='content')),
(
'cover',
models.ImageField(
blank=True,
null=True,
upload_to=dynamic_filenames.FilePattern(
filename_pattern='cover/{uuid:s}{ext}'
),
verbose_name='cover',
),
),
(
'comments',
models.ManyToManyField(
blank=True,
related_name='comments',
to='comment.comment',
verbose_name='comments',
),
),
],
options={
'verbose_name': 'Quib',
'verbose_name_plural': 'Quibs',
'ordering': ['-created_at'],
},
),
]
Loading

0 comments on commit 164ec9b

Please sign in to comment.