Minor optimizations for public API endpoints (#5172)
- Add/update eager loading for public API serializers - Use cached final schedule to get currently on-call users
This commit is contained in:
parent
673d2e9595
commit
e0816dd1ff
14 changed files with 40 additions and 13 deletions
|
|
@ -2,14 +2,17 @@ from rest_framework import serializers
|
|||
|
||||
from apps.alerts.models import EscalationChain
|
||||
from common.api_helpers.custom_fields import TeamPrimaryKeyRelatedField
|
||||
from common.api_helpers.mixins import EagerLoadingMixin
|
||||
from common.api_helpers.utils import CurrentOrganizationDefault
|
||||
|
||||
|
||||
class EscalationChainSerializer(serializers.ModelSerializer):
|
||||
class EscalationChainSerializer(EagerLoadingMixin, serializers.ModelSerializer):
|
||||
id = serializers.ReadOnlyField(source="public_primary_key")
|
||||
organization = serializers.HiddenField(default=CurrentOrganizationDefault())
|
||||
team_id = TeamPrimaryKeyRelatedField(required=False, allow_null=True, source="team")
|
||||
|
||||
SELECT_RELATED = ["organization", "team"]
|
||||
|
||||
class Meta:
|
||||
model = EscalationChain
|
||||
fields = (
|
||||
|
|
|
|||
|
|
@ -107,7 +107,13 @@ class EscalationPolicySerializer(EagerLoadingMixin, OrderedModelSerializer):
|
|||
]
|
||||
|
||||
PREFETCH_RELATED = ["notify_to_users_queue"]
|
||||
SELECT_RELATED = ["escalation_chain"]
|
||||
SELECT_RELATED = [
|
||||
"custom_webhook",
|
||||
"escalation_chain",
|
||||
"notify_schedule",
|
||||
"notify_to_group",
|
||||
"notify_to_team_members",
|
||||
]
|
||||
|
||||
@cached_property
|
||||
def escalation_chain(self):
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ class IntegrationSerializer(EagerLoadingMixin, serializers.ModelSerializer, Main
|
|||
description_short = serializers.CharField(max_length=250, required=False, allow_null=True)
|
||||
|
||||
PREFETCH_RELATED = ["channel_filters"]
|
||||
SELECT_RELATED = ["organization", "integration_heartbeat"]
|
||||
SELECT_RELATED = ["organization", "integration_heartbeat", "team"]
|
||||
|
||||
class Meta:
|
||||
model = AlertReceiveChannel
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ class CustomOnCallShiftSerializer(EagerLoadingMixin, serializers.ModelSerializer
|
|||
"source": {"required": False, "write_only": True},
|
||||
}
|
||||
|
||||
SELECT_RELATED = ["schedule"]
|
||||
SELECT_RELATED = ["organization", "team", "schedule"]
|
||||
PREFETCH_RELATED = ["schedules", "users"]
|
||||
|
||||
def create(self, validated_data):
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ from apps.alerts.models import AlertReceiveChannel, ChannelFilter, EscalationCha
|
|||
from apps.base.messaging import get_messaging_backend_from_id, get_messaging_backends
|
||||
from common.api_helpers.custom_fields import OrganizationFilteredPrimaryKeyRelatedField
|
||||
from common.api_helpers.exceptions import BadRequest
|
||||
from common.api_helpers.mixins import EagerLoadingMixin
|
||||
from common.api_helpers.utils import valid_jinja_template_for_serializer_method_field
|
||||
from common.jinja_templater.apply_jinja_template import JinjaTemplateError
|
||||
from common.ordered_model.serializer import OrderedModelSerializer
|
||||
|
|
@ -129,7 +130,7 @@ class RoutingTypeField(fields.CharField):
|
|||
raise BadRequest(detail="Invalid route type")
|
||||
|
||||
|
||||
class ChannelFilterSerializer(BaseChannelFilterSerializer):
|
||||
class ChannelFilterSerializer(EagerLoadingMixin, BaseChannelFilterSerializer):
|
||||
id = serializers.CharField(read_only=True, source="public_primary_key")
|
||||
slack = serializers.DictField(required=False)
|
||||
telegram = serializers.DictField(required=False)
|
||||
|
|
@ -146,6 +147,8 @@ class ChannelFilterSerializer(BaseChannelFilterSerializer):
|
|||
|
||||
is_the_last_route = serializers.BooleanField(read_only=True, source="is_default")
|
||||
|
||||
SELECT_RELATED = ["alert_receive_channel", "escalation_chain"]
|
||||
|
||||
class Meta:
|
||||
model = ChannelFilter
|
||||
fields = OrderedModelSerializer.Meta.fields + [
|
||||
|
|
|
|||
|
|
@ -6,21 +6,26 @@ from apps.schedules.ical_utils import list_users_to_notify_from_ical
|
|||
from apps.slack.models import SlackUserGroup
|
||||
from common.api_helpers.custom_fields import TeamPrimaryKeyRelatedField
|
||||
from common.api_helpers.exceptions import BadRequest
|
||||
from common.api_helpers.mixins import EagerLoadingMixin
|
||||
|
||||
|
||||
class ScheduleBaseSerializer(serializers.ModelSerializer):
|
||||
class ScheduleBaseSerializer(EagerLoadingMixin, serializers.ModelSerializer):
|
||||
id = serializers.CharField(read_only=True, source="public_primary_key")
|
||||
on_call_now = serializers.SerializerMethodField()
|
||||
slack = serializers.DictField(required=False)
|
||||
team_id = TeamPrimaryKeyRelatedField(required=False, allow_null=True, source="team")
|
||||
|
||||
SELECT_RELATED = ["team"]
|
||||
|
||||
def create(self, validated_data):
|
||||
validated_data = self._correct_validated_data(validated_data)
|
||||
validated_data["organization"] = self.context["request"].auth.organization
|
||||
return super().create(validated_data)
|
||||
|
||||
def get_on_call_now(self, obj):
|
||||
users_on_call = list_users_to_notify_from_ical(obj, datetime.datetime.now(datetime.timezone.utc))
|
||||
users_on_call = list_users_to_notify_from_ical(
|
||||
obj, datetime.datetime.now(datetime.timezone.utc), from_cached_final=True
|
||||
)
|
||||
if users_on_call is not None:
|
||||
return [user.public_primary_key for user in users_on_call]
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -5,11 +5,10 @@ from apps.schedules.tasks import (
|
|||
schedule_notify_about_empty_shifts_in_schedule,
|
||||
schedule_notify_about_gaps_in_schedule,
|
||||
)
|
||||
from common.api_helpers.custom_fields import TeamPrimaryKeyRelatedField, TimeZoneField, UsersFilteredByOrganizationField
|
||||
from common.api_helpers.custom_fields import TimeZoneField, UsersFilteredByOrganizationField
|
||||
|
||||
|
||||
class ScheduleWebSerializer(ScheduleBaseSerializer):
|
||||
team_id = TeamPrimaryKeyRelatedField(required=False, allow_null=True, source="team")
|
||||
time_zone = TimeZoneField(required=True)
|
||||
shifts = UsersFilteredByOrganizationField(
|
||||
queryset=CustomOnCallShift.objects,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ from apps.webhooks.models.webhook import PUBLIC_WEBHOOK_HTTP_METHODS, WEBHOOK_FI
|
|||
from apps.webhooks.presets.preset_options import WebhookPresetOptions
|
||||
from common.api_helpers.custom_fields import IntegrationFilteredByOrganizationField, TeamPrimaryKeyRelatedField
|
||||
from common.api_helpers.exceptions import BadRequest
|
||||
from common.api_helpers.mixins import EagerLoadingMixin
|
||||
from common.api_helpers.utils import CurrentOrganizationDefault, CurrentTeamDefault, CurrentUserDefault
|
||||
from common.jinja_templater import apply_jinja_template
|
||||
from common.jinja_templater.apply_jinja_template import JinjaTemplateError, JinjaTemplateWarning
|
||||
|
|
@ -48,7 +49,7 @@ class WebhookResponseSerializer(serializers.ModelSerializer):
|
|||
]
|
||||
|
||||
|
||||
class WebhookCreateSerializer(serializers.ModelSerializer):
|
||||
class WebhookCreateSerializer(EagerLoadingMixin, serializers.ModelSerializer):
|
||||
id = serializers.CharField(read_only=True, source="public_primary_key")
|
||||
organization = serializers.HiddenField(default=CurrentOrganizationDefault())
|
||||
team = TeamPrimaryKeyRelatedField(allow_null=True, default=CurrentTeamDefault())
|
||||
|
|
@ -58,6 +59,8 @@ class WebhookCreateSerializer(serializers.ModelSerializer):
|
|||
source="filtered_integrations", many=True, required=False
|
||||
)
|
||||
|
||||
SELECT_RELATED = ["organization", "team"]
|
||||
|
||||
class Meta:
|
||||
model = Webhook
|
||||
fields = [
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ class EscalationChainView(RateLimitHeadersMixin, ModelViewSet):
|
|||
if name is not None:
|
||||
queryset = queryset.filter(name=name)
|
||||
|
||||
queryset = self.serializer_class.setup_eager_loading(queryset)
|
||||
return queryset.order_by("id")
|
||||
|
||||
def get_object(self):
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
from django.db.models import Count
|
||||
from django_filters import rest_framework as filters
|
||||
from rest_framework.exceptions import NotFound
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
|
|
@ -47,7 +46,6 @@ class IntegrationView(
|
|||
queryset = queryset.filter(verbal_name=name)
|
||||
queryset = self.filter_queryset(queryset)
|
||||
queryset = self.serializer_class.setup_eager_loading(queryset)
|
||||
queryset = queryset.annotate(alert_groups_count_annotated=Count("alert_groups", distinct=True))
|
||||
|
||||
return queryset
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ class ChannelFilterView(RateLimitHeadersMixin, UpdateSerializerMixin, ModelViewS
|
|||
queryset = ChannelFilter.objects.filter(
|
||||
alert_receive_channel__organization=self.request.auth.organization, alert_receive_channel__deleted_at=None
|
||||
)
|
||||
queryset = self.serializer_class.setup_eager_loading(queryset)
|
||||
|
||||
if integration_id:
|
||||
queryset = queryset.filter(alert_receive_channel__public_primary_key=integration_id)
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ class OnCallScheduleChannelView(RateLimitHeadersMixin, UpdateSerializerMixin, Mo
|
|||
if name is not None:
|
||||
queryset = queryset.filter(name=name)
|
||||
|
||||
queryset = self.serializer_class.setup_eager_loading(queryset)
|
||||
return queryset.order_by("id")
|
||||
|
||||
def get_object(self):
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ class WebhooksView(RateLimitHeadersMixin, UpdateSerializerMixin, ModelViewSet):
|
|||
if webhook_name:
|
||||
queryset = queryset.filter(name=webhook_name)
|
||||
|
||||
queryset = self.serializer_class.setup_eager_loading(queryset)
|
||||
return queryset.order_by("id")
|
||||
|
||||
def get_object(self):
|
||||
|
|
|
|||
|
|
@ -344,6 +344,7 @@ def list_of_empty_shifts_in_schedule(
|
|||
def list_users_to_notify_from_ical(
|
||||
schedule: "OnCallSchedule",
|
||||
events_datetime: typing.Optional[datetime.datetime] = None,
|
||||
from_cached_final: bool = False,
|
||||
) -> typing.Sequence["User"]:
|
||||
"""
|
||||
Retrieve on-call users for the current time
|
||||
|
|
@ -353,6 +354,7 @@ def list_users_to_notify_from_ical(
|
|||
schedule,
|
||||
events_datetime,
|
||||
events_datetime,
|
||||
from_cached_final=from_cached_final,
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -360,8 +362,12 @@ def list_users_to_notify_from_ical_for_period(
|
|||
schedule: "OnCallSchedule",
|
||||
start_datetime: datetime.datetime,
|
||||
end_datetime: datetime.datetime,
|
||||
from_cached_final: bool = False,
|
||||
) -> typing.Sequence["User"]:
|
||||
events = schedule.final_events(start_datetime, end_datetime)
|
||||
if from_cached_final and schedule.cached_ical_final_schedule:
|
||||
events = schedule.filter_events(start_datetime, end_datetime, from_cached_final=True)
|
||||
else:
|
||||
events = schedule.final_events(start_datetime, end_datetime)
|
||||
usernames: typing.List[str] = []
|
||||
for event in events:
|
||||
usernames += [u["email"] for u in event.get("users", [])]
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue