Why i am having a duplicate data when i tried to apply a sorting with django-rest-framework.
I have this on my settings.py
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": (
"rest_framework.authentication.BasicAuthentication",
"rest_framework.authentication.SessionAuthentication",
"rest_framework_simplejwt.authentication.JWTAuthentication",
"dj_rest_auth.jwt_auth.JWTCookieAuthentication",
),
"DEFAULT_PERMISSION_CLASSES": ("rest_framework.permissions.IsAuthenticated",),
"DEFAULT_FILTER_BACKENDS": (
"django_filters.rest_framework.DjangoFilterBackend",
"rest_framework.filters.OrderingFilter",
),
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.LimitOffsetPagination",
"PAGE_SIZE": 10
}
then i have this serializer
class PersonListSerializer(serializers.ModelSerializer):
org = OrgSerializer(many=False)
# prompts = PromptResponseSerializer(read_only=True, many=True)
# emails = EmailSerializer(read_only=True, many=True)
custom_fields = PersonCustomFieldValueSerializer(many=True)
tags = TagSerializer(many=True, default=[])
total_click_count = serializers.IntegerField(read_only=True)
total_opened = serializers.IntegerField(read_only=True)
total_reply = serializers.IntegerField(read_only=True)
total_email_sent = serializers.IntegerField(read_only=True)
scheduled_emails = serializers.SerializerMethodField()
class Meta:
model = Person
fields = [
"id",
"first_name",
"last_name",
"job_title",
"company_name",
"work_email",
"company_website",
"sent_emails",
"last_contacted",
"next_scheduled_email",
"custom_fields",
"org",
"tags",
"total_click_count",
"total_opened",
"total_reply",
"total_email_sent",
"got_data",
"force_enable",
"assigned_user",
"status",
"person_city",
"state",
"industry",
"phone",
"linkedin",
"scheduled_emails",
]
def get_scheduled_emails(self, obj):
return EmailSerializer(obj.get_scheduled_emails(), many=True).data
def get_user_created_emails(self, _obj):
return _obj.emails.filter(created_by=self.context["request"].user)
def to_representation(self, obj):
representation = super().to_representation(obj)
# Calculate sent_email_count
sent_email_count = obj.emails.filter(
status=0, created_by=self.context["request"].user
).count()
total_click_count = sum(
click_count or 0
for email in self.get_user_created_emails(obj)
for click_count in email.click_tracking.values_list(
"click_count", flat=True
)
)
opened_emails = [
email
for email in self.get_user_created_emails(obj)
if hasattr(email, "trackings") and email.trackings.opened
]
total_reply_count = (
self.get_user_created_emails(obj).aggregate(
total_reply_count=Sum("reply_count__count")
)["total_reply_count"]
or 0
)
# Update the total_email_sent field in the representation
representation['total_email_sent'] = sent_email_count
representation['total_click_count'] = total_click_count
representation['total_opened'] = len(opened_emails)
representation['total_reply_count'] = total_reply_count
return representation
after that i tried to implement a sorting on my ModelViewSet views, but when i go to pages on my table since i have implemented a pagination of 10 per page, then i keep having duplicate data when i tried to sort. Why ?
Here is my ViewSet:
class PersonViewSet(ModelViewSet):
search_fields = [
"first_name",
"last_name",
"job_title",
"company_website",
"industry",
"work_email",
"person_city",
"state",
"email_domain",
"linkedin",
"got_data",
"org__industry",
"org__name",
"org__domain",
"assigned_user",
]
filter_backends = (
filters.SearchFilter,
filters.OrderingFilter,
DjangoFilterBackend,
)
ordering_fields = [
"first_name",
"got_data",
"assigned_user",
"job_title",
"company_name",
"company_website",
"industry",
"work_email",
"sent_emails",
"org__name",
"last_contacted",
"next_scheduled_email",
"total_click_count",
"total_opened",
"total_reply_count",
"total_email_sent",
]
filterset_class = PersonFilter
queryset = Person.objects.all()
def create(self, request, *args, **kwargs):
# Check if a user with the same email already exists
user = request.user
existing_user = Person.objects.filter(
work_email=request.data.get("work_email"),
team_id=user.team,
).first()
if existing_user:
return Response(
{
"detail": "A person with this email already exists for this user's team."
},
status=status.HTTP_400_BAD_REQUEST,
)
return super().create(request, *args, **kwargs)
def get_queryset(self, *args, **kwargs):
if self.request.user.team:
queryset = self.request.user.team.leads.all()
else:
queryset = super().get_queryset(*args, **kwargs)
ordering = self.request.query_params.get("ordering", "")
if ordering == "total_email_sent":
queryset = queryset.annotate(
total_email_sent=Count(
"emails",
filter=models.Q(
emails__status=0, emails__created_by=self.request.user
),
)
).order_by("total_email_sent")
elif ordering == "-total_email_sent":
queryset = queryset.annotate(
total_email_sent=Count(
"emails",
filter=models.Q(
emails__status=0, emails__created_by=self.request.user
),
)
).order_by("total_email_sent")
else:
queryset = queryset.order_by("-id")
print(str(queryset.query))
return queryset