1
+ from http import HTTPMethod
2
+ from itertools import chain
3
+
1
4
from django .conf import settings
5
+ from django .db .models import CharField , QuerySet , Value
2
6
from drf_spectacular .utils import extend_schema
3
- from rest_framework import exceptions , filters , permissions , viewsets
7
+ from rest_framework import exceptions , filters , permissions , response , viewsets
8
+ from rest_framework .decorators import action
4
9
10
+ from apps .api .serializers .comment import CommentDetailSerializer
11
+ from apps .api .serializers .post import PostSerializer
12
+ from apps .api .serializers .user .profile import ProfileSerializer
13
+ from apps .api .serializers .user .profile .downvoted import DownvotedSerializer
14
+ from apps .api .serializers .user .profile .overview import OverviewSerializer
15
+ from apps .api .serializers .user .profile .upvoted import UpvotedSerializer
5
16
from apps .user .models import Profile
6
17
7
- from ...serializers .user .profile import ProfileSerializer
8
-
9
18
10
- @extend_schema (tags = [' user & profiles' ])
19
+ @extend_schema (tags = [" user & profiles" ])
11
20
class ProfileViewSet (viewsets .ReadOnlyModelViewSet ):
12
21
"""
13
22
ViewSet for performing read-only operations on the Profile model.
@@ -19,10 +28,105 @@ class ProfileViewSet(viewsets.ReadOnlyModelViewSet):
19
28
queryset = Profile .objects .all ()
20
29
serializer_class = ProfileSerializer
21
30
filter_backends = (filters .SearchFilter ,)
22
- search_fields = ('username' ,)
31
+ search_fields = ("username" ,)
32
+
33
+ serializer_classes = {
34
+ "overview" : OverviewSerializer ,
35
+ "posts" : PostSerializer ,
36
+ "comments" : CommentDetailSerializer ,
37
+ "upvoted" : UpvotedSerializer ,
38
+ "downvoted" : DownvotedSerializer ,
39
+ }
40
+
41
+ def get_serializer_class (self ):
42
+ if self .action in self .serializer_classes :
43
+ return self .serializer_classes [self .action ]
44
+ return self .serializer_class
45
+
46
+ def get_queryset (self ) -> QuerySet [Profile ]:
47
+ return super ().get_queryset ()
48
+
49
+ def get_object (self ) -> Profile :
50
+ qs = self .get_queryset ()
51
+ filter_kwargs = {f"{ self .lookup_field } " : self .kwargs [self .lookup_field ]}
52
+ obj = qs .filter (** filter_kwargs ).first ()
53
+
54
+ if not obj :
55
+ raise exceptions .NotFound (
56
+ f"Profile with ID { self .kwargs [self .lookup_field ]} not found."
57
+ )
58
+ return obj
59
+
60
+ @extend_schema (responses = OverviewSerializer (many = True ))
61
+ @action (detail = True , methods = [HTTPMethod .GET ])
62
+ def overview (self , request , pk = None ):
63
+ """Returns a mixed list of posts and comments by the user, ordered by date."""
64
+ profile = self .get_object ()
65
+ posts = profile .posts .all ().annotate (type = Value ("post" , CharField ()))
66
+ comments = profile .comments .with_annotated_ratio ().annotate (
67
+ type = Value ("comment" , CharField ())
68
+ )
69
+
70
+ combined_data = sorted (chain (posts , comments ), key = lambda obj : obj .created_at , reverse = True )
71
+ serialized_data = self .get_serializer (
72
+ combined_data , context = {'request' : request }, many = True
73
+ ).data
74
+ return response .Response (serialized_data )
75
+
76
+ @extend_schema (responses = PostSerializer (many = True ))
77
+ @action (detail = True , methods = [HTTPMethod .GET ])
78
+ def posts (self , request , pk = None ):
79
+ """Returns a list of posts by the user, ordered by date."""
80
+ profile = self .get_object ()
81
+ posts = profile .posts .all ().order_by ("-created_at" )
82
+ serialized_data = self .get_serializer (posts , context = {"request" : request }, many = True ).data
83
+ return response .Response (serialized_data )
84
+
85
+ @extend_schema (responses = CommentDetailSerializer (many = True ))
86
+ @action (detail = True , methods = [HTTPMethod .GET ])
87
+ def comments (self , request , pk = None ):
88
+ """Returns a list of comments by the user, ordered by date."""
89
+ profile = self .get_object ()
90
+ comments = profile .comments .with_annotated_ratio ().order_by ("-created_at" )
91
+ serialized_data = self .get_serializer (
92
+ comments , context = {"request" : request }, many = True
93
+ ).data
94
+ return response .Response (serialized_data )
95
+
96
+ @extend_schema (responses = UpvotedSerializer (many = True ))
97
+ @action (detail = True , methods = [HTTPMethod .GET ])
98
+ def upvoted (self , request , pk = None ):
99
+ """Returns a mixed list of upvoted posts and comments by the user, ordered by date."""
100
+ profile = self .get_object ()
101
+ posts = profile .upvoted_posts .all ().annotate (type = Value ("post" , CharField ()))
102
+ comments = profile .upvoted_comments .with_annotated_ratio ().annotate (
103
+ type = Value ("comment" , CharField ())
104
+ )
105
+
106
+ combined_data = sorted (chain (posts , comments ), key = lambda obj : obj .created_at , reverse = True )
107
+ serialized_data = self .get_serializer (
108
+ combined_data , context = {"request" : request }, many = True
109
+ ).data
110
+ return response .Response (serialized_data )
111
+
112
+ @extend_schema (responses = DownvotedSerializer (many = True ))
113
+ @action (detail = True , methods = [HTTPMethod .GET ])
114
+ def downvoted (self , request , pk = None ):
115
+ """Returns a mixed list of downvoted posts and comments by the user, ordered by date."""
116
+ profile = self .get_object ()
117
+ posts = profile .downvoted_posts .all ().annotate (type = Value ("post" , CharField ()))
118
+ comments = profile .downvoted_comments .with_annotated_ratio ().annotate (
119
+ type = Value ("comment" , CharField ())
120
+ )
121
+
122
+ combined_data = sorted (chain (posts , comments ), key = lambda obj : obj .created_at , reverse = True )
123
+ serialized_data = self .get_serializer (
124
+ combined_data , context = {"request" : request }, many = True
125
+ ).data
126
+ return response .Response (serialized_data )
23
127
24
128
25
- @extend_schema (tags = [' user & profiles' ])
129
+ @extend_schema (tags = [" user & profiles" ])
26
130
class MyProfilesViewSet (viewsets .ModelViewSet ):
27
131
"""
28
132
ViewSet to manage profiles associated with the authenticated user.
@@ -39,7 +143,7 @@ def get_queryset(self): # pyright: ignore
39
143
Restrict queryset to profiles owned by the currently authenticated user.
40
144
"""
41
145
# during schema generation
42
- if getattr (self , ' swagger_fake_view' , False ):
146
+ if getattr (self , " swagger_fake_view" , False ):
43
147
return Profile .objects .none ()
44
148
user = self .request .user
45
149
return user .profiles .all () # pyright: ignore
@@ -54,6 +158,6 @@ def perform_create(self, serializer):
54
158
user = self .request .user
55
159
if user .profiles .count () >= settings .PROFILE_LIMIT : # pyright: ignore
56
160
raise exceptions .ValidationError (
57
- f' A user cannot have more than { settings .PROFILE_LIMIT } profiles.'
161
+ f" A user cannot have more than { settings .PROFILE_LIMIT } profiles."
58
162
)
59
163
serializer .save (user = user )
0 commit comments