From 5a2560146d591b4828b34caadc9f9459ff36af2b Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Mon, 29 Dec 2025 13:58:52 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9D=20Add=20docstrings=20to=20`perf/da?= =?UTF-8?q?tabase-optimization`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Docstrings generation was requested by @NotoriousArnav. * https://github.com/NotoriousArnav/EventHorizon/pull/1#issuecomment-3696600176 The following files were modified: * `events/api_views.py` * `events/models.py` * `events/serializers.py` * `events/views.py` --- events/api_views.py | 35 +++++++++++++++++++++++++++++------ events/models.py | 13 ++++++++++++- events/serializers.py | 12 +++++++----- events/views.py | 26 +++++++++++++++++++++++++- 4 files changed, 73 insertions(+), 13 deletions(-) diff --git a/events/api_views.py b/events/api_views.py index 65f6932..f76fde5 100644 --- a/events/api_views.py +++ b/events/api_views.py @@ -45,9 +45,12 @@ class EventViewSet(viewsets.ModelViewSet): def get_queryset(self): """ - Optimized queryset with: - - select_related for organizer (avoids N+1 on organizer access) - - Exists annotation for is_registered (avoids N+1 per-event query) + Return the Event queryset for this view, optimized for organizer access and optionally annotated with the requesting user's registration status. + + The queryset is ordered by `start_time` descending and includes related organizer information for efficient access. If the request user is authenticated, each Event will be annotated with `is_registered_annotation` (a boolean indicating whether that user has a Registration for the event). + + Returns: + QuerySet: Event queryset ordered by newest `start_time` first, with related organizer selected and `is_registered_annotation` added for authenticated users. """ queryset = Event.objects.select_related("organizer").order_by("-start_time") @@ -67,6 +70,12 @@ def get_queryset(self): return queryset def perform_create(self, serializer): + """ + Save a new Event instance and assign the current user as its organizer. + + Parameters: + serializer: Serializer instance with validated event data; `save` is called with `organizer` set to the requesting user. + """ serializer.save(organizer=self.request.user) @action( @@ -152,7 +161,12 @@ def unregister(self, request, pk=None): detail=True, methods=["get"], permission_classes=[permissions.IsAuthenticated] ) def registrations(self, request, pk=None): - """Get all registrations for an event (organizer only).""" + """ + Retrieve registrations for a specific event; access is limited to the event's organizer. + + Returns: + registrations (list): Serialized registration objects for the event, ordered by most recent. + """ event = self.get_object() @@ -178,9 +192,18 @@ class RegistrationViewSet(viewsets.ReadOnlyModelViewSet): permission_classes = [permissions.IsAuthenticated] def get_queryset(self): - """Optimized queryset with select_related for event and participant.""" + """ + Return the queryset of Registration objects belonging to the requesting user. + + The queryset is ordered by `registered_at` descending and includes the related + `event` and `participant` via `select_related` for query efficiency. + + Returns: + QuerySet[Registration]: Registrations for the authenticated request user, + ordered newest first, with `event` and `participant` selected. + """ return ( Registration.objects.filter(participant=self.request.user) .select_related("event", "participant") .order_by("-registered_at") - ) + ) \ No newline at end of file diff --git a/events/models.py b/events/models.py index 845a426..c2df084 100644 --- a/events/models.py +++ b/events/models.py @@ -45,6 +45,11 @@ class Meta: ] def save(self, *args, **kwargs): + """ + Ensure the model has a unique slug and save it to the database. + + If the instance's slug is empty, generate one from the title (fall back to a UUID hex). Attempt to save up to five times; on an IntegrityError caused by the slug, append a short UUID suffix and retry. Re-raise the error if it is not slug-related or if all attempts fail. + """ if not self.slug: base_slug = slugify(self.title) or uuid4().hex self.slug = base_slug @@ -90,6 +95,12 @@ class Meta: ] def __str__(self): + """ + Human-readable representation of the registration combining the participant and event title. + + Returns: + str: A string in the format " - ". + """ return f"{self.participant} - {self.event.title}" @@ -103,4 +114,4 @@ class Webhook(models.Model): is_active = models.BooleanField(default=True) def __str__(self): - return f"Webhook for {self.event.title} ({self.url})" + return f"Webhook for {self.event.title} ({self.url})" \ No newline at end of file diff --git a/events/serializers.py b/events/serializers.py index 83e5f86..c8b470a 100644 --- a/events/serializers.py +++ b/events/serializers.py @@ -54,10 +54,12 @@ class Meta: def get_is_registered(self, obj): """ - Check if the current user is registered for this event. - - Optimized to use the pre-annotated value from the queryset when available, - falling back to a database query for detail views or when annotation is missing. + Determine whether the current request user is registered for the given event. + + This prefers a pre-annotated `is_registered_annotation` on the event object when present (to avoid extra queries in list views); otherwise it checks the database for a registration for the authenticated request user. + + Returns: + `true` if the current request user is registered for the event, `false` otherwise. """ # Use annotated value if available (from list views with Exists() annotation) # This avoids N+1 queries when listing multiple events @@ -89,4 +91,4 @@ class Meta: "registered_at", "answers", ] - read_only_fields = ["participant", "status", "registered_at", "event"] + read_only_fields = ["participant", "status", "registered_at", "event"] \ No newline at end of file diff --git a/events/views.py b/events/views.py index 7565703..d6793bb 100644 --- a/events/views.py +++ b/events/views.py @@ -99,6 +99,16 @@ class EventListView(ListView): paginate_by = 6 def get_queryset(self): + """ + Return the Event queryset filtered by optional `q` (title or description) and `location` GET parameters, with `organizer` and `organizer.profile` preloaded. + + Filters: + - `q`: case-insensitive substring match against `title` or `description`. + - `location`: case-insensitive substring match against `location`. + + Returns: + QuerySet: Event objects matching the provided filters with `organizer` and `organizer.profile` selected for eager loading. + """ queryset = ( super().get_queryset().select_related("organizer", "organizer__profile") ) @@ -128,6 +138,12 @@ class UserEventListView(LoginRequiredMixin, ListView): context_object_name = "hosted_events" def get_queryset(self): + """ + Retrieve the current user's events with organizer and organizer profile eager-loaded, ordered by start_time. + + Returns: + QuerySet[Event]: Events organized by the request's user with `organizer` and `organizer__profile` selected and ordered by `start_time`. + """ return ( Event.objects.filter(organizer=self.request.user) .select_related("organizer", "organizer__profile") @@ -135,6 +151,14 @@ def get_queryset(self): ) def get_context_data(self, **kwargs): + """ + Add the current user's registrations to the template context under the key "attended_registrations". + + The value is a queryset of Registration objects for the requesting user, eager-loading related event and organizer (including organizer profile) and ordered by the related event's start_time. + + Returns: + context (dict): Template context including "attended_registrations". + """ context = super().get_context_data(**kwargs) context["attended_registrations"] = ( Registration.objects.filter(participant=self.request.user) @@ -467,4 +491,4 @@ def post(self, request, pk): def test_func(self): webhook = get_object_or_404(Webhook, pk=self.kwargs["pk"]) - return self.request.user == webhook.event.organizer + return self.request.user == webhook.event.organizer \ No newline at end of file