Skip to content

Feat/devltz/reviews#17

Merged
DevlTz merged 14 commits into
mainfrom
feat/devltz/reviews
Apr 8, 2026
Merged

Feat/devltz/reviews#17
DevlTz merged 14 commits into
mainfrom
feat/devltz/reviews

Conversation

@DevlTz
Copy link
Copy Markdown
Owner

@DevlTz DevlTz commented Apr 1, 2026

No description provided.

@DevlTz DevlTz requested review from Copilot and luisaferreirass and removed request for luisaferreirass April 7, 2026 20:09
@DevlTz DevlTz self-assigned this Apr 7, 2026
@DevlTz DevlTz added help wanted Extra attention is needed new code New code that's working correctly backend backend do projeto labels Apr 7, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a reviews feature for properties, including a new Reviews model + migration, review validation, and API endpoints for listing/creating reviews and exposing average rating on property reads.

Changes:

  • Added Reviews model with a DB-level uniqueness constraint (one review per user per property) and corresponding migration.
  • Added review validators + a ReviewsSerializer.
  • Added nested review routes under properties and exposed average_rating on PropertiesReadSerializer.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
apps/properties/views/property_views.py Adds review list/create + review RUD views and related permission helpers.
apps/properties/validators.py Adds validators for rating range and comment length.
apps/properties/urls.py Adds nested /properties/<pk>/reviews/ routes and search/ route.
apps/properties/serializers/reviews_serializers.py Implements ReviewsSerializer including duplicate-review validation.
apps/properties/serializers/property_serializers.py Adds average_rating field to property read serializer.
apps/properties/models.py Adds the Reviews model and uniqueness constraint.
apps/properties/migrations/0003_reviews.py Creates the reviews table and constraint.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +54 to +61
class RUDReviewPropertyView(generics.RetrieveUpdateDestroyAPIView):
queryset = Properties.objects.all()
lookup_field = "pk"

def get_permissions(self):
if self.request.method in ["PUT", "PATCH", "DELETE"]:
return [IsAuthenticated(), IsPropertyOwner()]
return [AllowAny()]
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RUDReviewPropertyView is wired as a review detail endpoint, but it currently queries Properties and looks up by pk, while the URL provides review_pk. This will retrieve the wrong model (or 404) and will also fail because no serializer_class/get_serializer_class is defined for this view. Update it to operate on Reviews (and filter by the parent property), align the lookup kwarg with review_pk, and use object-level permissions appropriate for review ownership (e.g., IsReviewOwner) for update/delete.

Copilot uses AI. Check for mistakes.
Comment thread apps/properties/views/property_views.py Outdated
Comment on lines 3 to 6
from rest_framework import generics, status, serializers
from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework.permissions import BasePermission
from rest_framework.exceptions import PermissionDenied
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused imports (status, serializers, PermissionDenied) were introduced here. Please remove them or use them (e.g., status.HTTP_204_NO_CONTENT), since unused imports can break lint/CI and add confusion.

Suggested change
from rest_framework import generics, status, serializers
from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework.permissions import BasePermission
from rest_framework.exceptions import PermissionDenied
from rest_framework import generics
from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework.permissions import BasePermission

Copilot uses AI. Check for mistakes.
Comment thread apps/properties/views/property_views.py Outdated
@@ -75,6 +112,5 @@ def destroy(self, request, *args, **kwargs):
"message": "Delete successfull!"
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Response message has a spelling error: "successfull" should be "successful".

Suggested change
"message": "Delete successfull!"
"message": "Delete successful!"

Copilot uses AI. Check for mistakes.
Comment thread apps/properties/urls.py
#path("search/filters/", property_views.FilterPropertyView.as_view()),
path("search/", property_views.SearchPropertyAIView.as_view()),
path("<int:pk>/reviews/", property_views.CreateListReviewPropertyView.as_view()),
path("<int:pk>/reviews/<int:review_pk>/", property_views.RUDReviewPropertyView.as_view()),
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This route provides review_pk, but the corresponding view currently uses lookup_field = "pk" and doesn't reference review_pk, so the endpoint won't resolve the intended review. Align the view's lookup kwarg/field with this URL pattern (and ensure it queries Reviews, not Properties).

Suggested change
path("<int:pk>/reviews/<int:review_pk>/", property_views.RUDReviewPropertyView.as_view()),
path("<int:property_pk>/reviews/<int:pk>/", property_views.RUDReviewPropertyView.as_view()),

Copilot uses AI. Check for mistakes.
def validate(self, data):
request = self.context.get("request")
property_id = self.context.get("property_id")
if Reviews.objects.filter(user=request.user, property_id=property_id).exists():
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

validate() enforces a unique (user, property) review unconditionally; this will also raise on updates (it finds the existing review, which may be the instance being updated). Adjust the check to only run on create (when self.instance is None) or exclude self.instance.pk from the query. Also consider deriving property_id from self.instance.property_id if it's not present in serializer context.

Suggested change
if Reviews.objects.filter(user=request.user, property_id=property_id).exists():
if property_id is None and self.instance is not None:
property_id = self.instance.property_id
queryset = Reviews.objects.filter(user=request.user, property_id=property_id)
if self.instance is not None and self.instance.pk is not None:
queryset = queryset.exclude(pk=self.instance.pk)
if queryset.exists():

Copilot uses AI. Check for mistakes.
@@ -1,7 +1,10 @@
from unittest import result
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from unittest import result appears to be an accidental/unused import and can shadow local variable names (you also use result inside get_average_rating). Please remove this import.

Suggested change
from unittest import result

Copilot uses AI. Check for mistakes.
images = PropertiesPhotosSerializer(many=True, read_only=True, source="photos")
average_rating = serializers.SerializerMethodField()

def get_average_rating(self, obj):
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_average_rating() performs an aggregate query per property instance. When serializing a list of properties, this will create an N+1 query pattern. Consider annotating the queryset with the average rating (or using prefetch_related + aggregation) in the view so the rating can be returned without per-row queries.

Suggested change
def get_average_rating(self, obj):
def get_average_rating(self, obj):
if hasattr(obj, "average_rating"):
return obj.average_rating

Copilot uses AI. Check for mistakes.
@DevlTz DevlTz merged commit a346255 into main Apr 8, 2026
1 of 2 checks passed
@DevlTz DevlTz deleted the feat/devltz/reviews branch May 16, 2026 04:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend backend do projeto help wanted Extra attention is needed new code New code that's working correctly

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants