fix: issue create update n+1 and issue activity get n+1 (#1606)

* fix: issue create update n+1 and issue activity get n+1

* dev: notifications n+1
This commit is contained in:
Nikhil 2023-07-24 12:23:34 +05:30 committed by GitHub
parent 8ff834c328
commit e83ef7332d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 87 additions and 56 deletions

View File

@ -115,8 +115,15 @@ class IssueCreateSerializer(BaseSerializer):
labels = validated_data.pop("labels_list", None) labels = validated_data.pop("labels_list", None)
blocks = validated_data.pop("blocks_list", None) blocks = validated_data.pop("blocks_list", None)
project = self.context["project"] project_id = self.context["project_id"]
issue = Issue.objects.create(**validated_data, project=project) workspace_id = self.context["workspace_id"]
default_assignee_id = self.context["default_assignee_id"]
issue = Issue.objects.create(**validated_data, project_id=project_id)
# Issue Audit Users
created_by_id = issue.created_by_id
updated_by_id = issue.updated_by_id
if blockers is not None and len(blockers): if blockers is not None and len(blockers):
IssueBlocker.objects.bulk_create( IssueBlocker.objects.bulk_create(
@ -124,10 +131,10 @@ class IssueCreateSerializer(BaseSerializer):
IssueBlocker( IssueBlocker(
block=issue, block=issue,
blocked_by=blocker, blocked_by=blocker,
project=project, project_id=project_id,
workspace=project.workspace, workspace_id=workspace_id,
created_by=issue.created_by, created_by_id=created_by_id,
updated_by=issue.updated_by, updated_by_id=updated_by_id,
) )
for blocker in blockers for blocker in blockers
], ],
@ -140,10 +147,10 @@ class IssueCreateSerializer(BaseSerializer):
IssueAssignee( IssueAssignee(
assignee=user, assignee=user,
issue=issue, issue=issue,
project=project, project_id=project_id,
workspace=project.workspace, workspace_id=workspace_id,
created_by=issue.created_by, created_by_id=created_by_id,
updated_by=issue.updated_by, updated_by_id=updated_by_id,
) )
for user in assignees for user in assignees
], ],
@ -151,14 +158,14 @@ class IssueCreateSerializer(BaseSerializer):
) )
else: else:
# Then assign it to default assignee # Then assign it to default assignee
if project.default_assignee is not None: if default_assignee_id is not None:
IssueAssignee.objects.create( IssueAssignee.objects.create(
assignee=project.default_assignee, assignee_id=default_assignee_id,
issue=issue, issue=issue,
project=project, project_id=project_id,
workspace=project.workspace, workspace_id=workspace_id,
created_by=issue.created_by, created_by_id=created_by_id,
updated_by=issue.updated_by, updated_by_id=updated_by_id,
) )
if labels is not None and len(labels): if labels is not None and len(labels):
@ -167,10 +174,10 @@ class IssueCreateSerializer(BaseSerializer):
IssueLabel( IssueLabel(
label=label, label=label,
issue=issue, issue=issue,
project=project, project_id=project_id,
workspace=project.workspace, workspace_id=workspace_id,
created_by=issue.created_by, created_by_id=created_by_id,
updated_by=issue.updated_by, updated_by_id=updated_by_id,
) )
for label in labels for label in labels
], ],
@ -183,10 +190,10 @@ class IssueCreateSerializer(BaseSerializer):
IssueBlocker( IssueBlocker(
block=block, block=block,
blocked_by=issue, blocked_by=issue,
project=project, project_id=project_id,
workspace=project.workspace, workspace_id=workspace_id,
created_by=issue.created_by, created_by_id=created_by_id,
updated_by=issue.updated_by, updated_by_id=updated_by_id,
) )
for block in blocks for block in blocks
], ],
@ -201,6 +208,12 @@ class IssueCreateSerializer(BaseSerializer):
labels = validated_data.pop("labels_list", None) labels = validated_data.pop("labels_list", None)
blocks = validated_data.pop("blocks_list", None) blocks = validated_data.pop("blocks_list", None)
# Related models
project_id = instance.project_id
workspace_id = instance.workspace_id
created_by_id = instance.created_by_id
updated_by_id = instance.updated_by_id
if blockers is not None: if blockers is not None:
IssueBlocker.objects.filter(block=instance).delete() IssueBlocker.objects.filter(block=instance).delete()
IssueBlocker.objects.bulk_create( IssueBlocker.objects.bulk_create(
@ -208,10 +221,10 @@ class IssueCreateSerializer(BaseSerializer):
IssueBlocker( IssueBlocker(
block=instance, block=instance,
blocked_by=blocker, blocked_by=blocker,
project=instance.project, project_id=project_id,
workspace=instance.project.workspace, workspace_id=workspace_id,
created_by=instance.created_by, created_by_id=created_by_id,
updated_by=instance.updated_by, updated_by_id=updated_by_id,
) )
for blocker in blockers for blocker in blockers
], ],
@ -225,10 +238,10 @@ class IssueCreateSerializer(BaseSerializer):
IssueAssignee( IssueAssignee(
assignee=user, assignee=user,
issue=instance, issue=instance,
project=instance.project, project_id=project_id,
workspace=instance.project.workspace, workspace_id=workspace_id,
created_by=instance.created_by, created_by_id=created_by_id,
updated_by=instance.updated_by, updated_by_id=updated_by_id,
) )
for user in assignees for user in assignees
], ],
@ -242,10 +255,10 @@ class IssueCreateSerializer(BaseSerializer):
IssueLabel( IssueLabel(
label=label, label=label,
issue=instance, issue=instance,
project=instance.project, project_id=project_id,
workspace=instance.project.workspace, workspace_id=workspace_id,
created_by=instance.created_by, created_by_id=created_by_id,
updated_by=instance.updated_by, updated_by_id=updated_by_id,
) )
for label in labels for label in labels
], ],
@ -259,16 +272,17 @@ class IssueCreateSerializer(BaseSerializer):
IssueBlocker( IssueBlocker(
block=block, block=block,
blocked_by=instance, blocked_by=instance,
project=instance.project, project_id=project_id,
workspace=instance.project.workspace, workspace_id=workspace_id,
created_by=instance.created_by, created_by_id=created_by_id,
updated_by=instance.updated_by, updated_by_id=updated_by_id,
) )
for block in blocks for block in blocks
], ],
batch_size=10, batch_size=10,
) )
# Time updation occues even when other related models are updated
instance.updated_at = timezone.now() instance.updated_at = timezone.now()
return super().update(instance, validated_data) return super().update(instance, validated_data)

View File

@ -270,9 +270,15 @@ class IssueViewSet(BaseViewSet):
def create(self, request, slug, project_id): def create(self, request, slug, project_id):
try: try:
project = Project.objects.get(workspace__slug=slug, pk=project_id) project = Project.objects.get(pk=project_id)
serializer = IssueCreateSerializer( serializer = IssueCreateSerializer(
data=request.data, context={"project": project} data=request.data,
context={
"project_id": project_id,
"workspace_id": project.workspace_id,
"default_assignee_id": project.default_assignee_id,
},
) )
if serializer.is_valid(): if serializer.is_valid():
@ -396,6 +402,7 @@ class IssueActivityEndpoint(BaseAPIView):
IssueComment.objects.filter(issue_id=issue_id) IssueComment.objects.filter(issue_id=issue_id)
.filter(project__project_projectmember__member=self.request.user) .filter(project__project_projectmember__member=self.request.user)
.order_by("created_at") .order_by("created_at")
.select_related("actor", "issue", "project", "workspace")
) )
issue_activities = IssueActivitySerializer(issue_activities, many=True).data issue_activities = IssueActivitySerializer(issue_activities, many=True).data
issue_comments = IssueCommentSerializer(issue_comments, many=True).data issue_comments = IssueCommentSerializer(issue_comments, many=True).data
@ -1096,7 +1103,8 @@ class IssueArchiveViewSet(BaseViewSet):
return Response(IssueSerializer(issue).data, status=status.HTTP_200_OK) return Response(IssueSerializer(issue).data, status=status.HTTP_200_OK)
except Issue.DoesNotExist: except Issue.DoesNotExist:
return Response( return Response(
{"error": "Issue Does not exist"}, status=status.HTTP_404_NOT_FOUND) {"error": "Issue Does not exist"}, status=status.HTTP_404_NOT_FOUND
)
except Exception as e: except Exception as e:
capture_exception(e) capture_exception(e)
return Response( return Response(
@ -1104,6 +1112,7 @@ class IssueArchiveViewSet(BaseViewSet):
status=status.HTTP_400_BAD_REQUEST, status=status.HTTP_400_BAD_REQUEST,
) )
class IssueSubscriberViewSet(BaseViewSet): class IssueSubscriberViewSet(BaseViewSet):
serializer_class = IssueSubscriberSerializer serializer_class = IssueSubscriberSerializer
model = IssueSubscriber model = IssueSubscriber
@ -1144,9 +1153,11 @@ class IssueSubscriberViewSet(BaseViewSet):
def list(self, request, slug, project_id, issue_id): def list(self, request, slug, project_id, issue_id):
try: try:
members = ProjectMember.objects.filter( members = (
ProjectMember.objects.filter(
workspace__slug=slug, project_id=project_id workspace__slug=slug, project_id=project_id
).annotate( )
.annotate(
is_subscribed=Exists( is_subscribed=Exists(
IssueSubscriber.objects.filter( IssueSubscriber.objects.filter(
workspace__slug=slug, workspace__slug=slug,
@ -1155,7 +1166,9 @@ class IssueSubscriberViewSet(BaseViewSet):
subscriber=OuterRef("member"), subscriber=OuterRef("member"),
) )
) )
).select_related("member") )
.select_related("member")
)
serializer = ProjectMemberLiteSerializer(members, many=True) serializer = ProjectMemberLiteSerializer(members, many=True)
return Response(serializer.data, status=status.HTTP_200_OK) return Response(serializer.data, status=status.HTTP_200_OK)
except Exception as e: except Exception as e:

View File

@ -38,9 +38,13 @@ class NotificationViewSet(BaseViewSet, BasePaginator):
# Filter type # Filter type
type = request.GET.get("type", "all") type = request.GET.get("type", "all")
notifications = Notification.objects.filter( notifications = (
Notification.objects.filter(
workspace__slug=slug, receiver_id=request.user.id workspace__slug=slug, receiver_id=request.user.id
).order_by("snoozed_till", "-created_at") )
.select_related("workspace", "project," "triggered_by", "receiver")
.order_by("snoozed_till", "-created_at")
)
# Filter for snoozed notifications # Filter for snoozed notifications
if snoozed == "false": if snoozed == "false":