Spaces:
Build error
Build error
| from django.db.models import Q, Case, When, Value, IntegerField | |
| from rest_framework import status | |
| from rest_framework.authtoken.models import Token | |
| from rest_framework.decorators import api_view, permission_classes | |
| from rest_framework.permissions import AllowAny, IsAuthenticated | |
| from rest_framework.response import Response | |
| from .models import User, Place, Review | |
| from .serializers import ( | |
| UserSerializer, | |
| PlaceSerializer, | |
| PlaceDetailSerializer, | |
| AddReviewSerializer | |
| ) | |
| def register(request): | |
| """ | |
| Register a new user with name and phone number. | |
| Request body: | |
| { | |
| "name": "John Doe", | |
| "phone": "1234567890" | |
| } | |
| Response: | |
| { | |
| "user": { | |
| "id": 1, | |
| "name": "John Doe", | |
| "phone": "1234567890" | |
| }, | |
| "token": "your-auth-token" | |
| } | |
| """ | |
| serializer = UserSerializer(data=request.data) | |
| if serializer.is_valid(): | |
| user = serializer.save() | |
| token, _ = Token.objects.get_or_create(user=user) | |
| return Response({ | |
| 'user': serializer.data, | |
| 'token': token.key | |
| }, status=status.HTTP_201_CREATED) | |
| return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) | |
| def login(request): | |
| """ | |
| Login with phone number to get authentication token. | |
| Request body: | |
| { | |
| "phone": "1234567890" | |
| } | |
| Response: | |
| { | |
| "user": { | |
| "id": 1, | |
| "name": "John Doe", | |
| "phone": "1234567890" | |
| }, | |
| "token": "your-auth-token" | |
| } | |
| """ | |
| phone = request.data.get('phone') | |
| if not phone: | |
| return Response( | |
| {'error': 'Phone number is required'}, | |
| status=status.HTTP_400_BAD_REQUEST | |
| ) | |
| try: | |
| user = User.objects.get(phone=phone) | |
| token, _ = Token.objects.get_or_create(user=user) | |
| return Response({ | |
| 'user': UserSerializer(user).data, | |
| 'token': token.key | |
| }) | |
| except User.DoesNotExist: | |
| return Response( | |
| {'error': 'User with this phone number does not exist'}, | |
| status=status.HTTP_404_NOT_FOUND | |
| ) | |
| def add_review(request): | |
| """ | |
| Add a review for a place. Creates the place if it doesn't exist. | |
| Request body: | |
| { | |
| "place_name": "Joe's Pizza", | |
| "place_address": "123 Main St, New York, NY", | |
| "rating": 5, | |
| "review_text": "Best pizza in town!" | |
| } | |
| Response: | |
| { | |
| "message": "Review added successfully", | |
| "review": { | |
| "id": 1, | |
| "user_name": "John Doe", | |
| "rating": 5, | |
| "text": "Best pizza in town!", | |
| "created_at": "2024-01-01T12:00:00Z" | |
| } | |
| } | |
| """ | |
| serializer = AddReviewSerializer( | |
| data=request.data, | |
| context={'request': request} | |
| ) | |
| if serializer.is_valid(): | |
| review = serializer.save() | |
| from .serializers import ReviewSerializer | |
| return Response({ | |
| 'message': 'Review added successfully', | |
| 'review': ReviewSerializer(review).data | |
| }, status=status.HTTP_201_CREATED) | |
| return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) | |
| def search_places(request): | |
| """ | |
| Search for places by name and/or minimum rating. | |
| Query parameters: | |
| - name (optional): Search by place name (exact match first, then partial) | |
| - min_rating (optional): Filter by minimum average rating | |
| Example: /api/places/search/?name=pizza&min_rating=4 | |
| Response: | |
| [ | |
| { | |
| "id": 1, | |
| "name": "Joe's Pizza", | |
| "address": "123 Main St, New York, NY", | |
| "average_rating": 4.5 | |
| } | |
| ] | |
| """ | |
| name_query = request.query_params.get('name', '').strip() | |
| min_rating = request.query_params.get('min_rating', None) | |
| # Start with all places | |
| queryset = Place.objects.all() | |
| # Filter by name if provided | |
| if name_query: | |
| # Use Q objects to combine exact and partial matches | |
| # Annotate with priority: 1 for exact match, 2 for partial match | |
| queryset = queryset.annotate( | |
| match_priority=Case( | |
| When(name__iexact=name_query, then=Value(1)), | |
| When(name__icontains=name_query, then=Value(2)), | |
| default=Value(3), | |
| output_field=IntegerField() | |
| ) | |
| ).filter( | |
| Q(name__iexact=name_query) | Q(name__icontains=name_query) | |
| ).order_by('match_priority', 'name') | |
| else: | |
| queryset = queryset.order_by('name') | |
| # Get all places and filter by rating in Python (since average is a property) | |
| places = list(queryset) | |
| if min_rating: | |
| try: | |
| min_rating_value = float(min_rating) | |
| places = [ | |
| place for place in places | |
| if place.average_rating is not None and place.average_rating >= min_rating_value | |
| ] | |
| except ValueError: | |
| return Response( | |
| {'error': 'Invalid min_rating value'}, | |
| status=status.HTTP_400_BAD_REQUEST | |
| ) | |
| serializer = PlaceSerializer(places, many=True) | |
| return Response(serializer.data) | |
| def place_detail(request, place_id): | |
| """ | |
| Get detailed information about a place including all reviews. | |
| Current user's review appears first, followed by others sorted by newest. | |
| Response: | |
| { | |
| "id": 1, | |
| "name": "Joe's Pizza", | |
| "address": "123 Main St, New York, NY", | |
| "average_rating": 4.5, | |
| "reviews": [ | |
| { | |
| "id": 1, | |
| "user_name": "John Doe", | |
| "rating": 5, | |
| "text": "Best pizza!", | |
| "created_at": "2024-01-01T12:00:00Z" | |
| } | |
| ] | |
| } | |
| """ | |
| try: | |
| place = Place.objects.get(pk=place_id) | |
| serializer = PlaceDetailSerializer( | |
| place, | |
| context={'request': request} | |
| ) | |
| return Response(serializer.data) | |
| except Place.DoesNotExist: | |
| return Response( | |
| {'error': 'Place not found'}, | |
| status=status.HTTP_404_NOT_FOUND | |
| ) | |