Assignment / reviews /serializers.py
Assignment User
Initial commit: Django REST API for place reviews
877587b
from rest_framework import serializers
from .models import User, Place, Review
class UserSerializer(serializers.ModelSerializer):
"""Serializer for user registration and display."""
class Meta:
model = User
fields = ['id', 'name', 'phone']
read_only_fields = ['id']
def create(self, validated_data):
"""Create a new user with phone authentication."""
user = User.objects.create_user(
phone=validated_data['phone'],
name=validated_data['name'],
username=validated_data['phone'] # Use phone as username
)
return user
class PlaceSerializer(serializers.ModelSerializer):
"""Serializer for place list/search results."""
average_rating = serializers.SerializerMethodField()
class Meta:
model = Place
fields = ['id', 'name', 'address', 'average_rating']
read_only_fields = ['id']
def get_average_rating(self, obj):
"""Get the average rating for this place."""
return obj.average_rating
class ReviewSerializer(serializers.ModelSerializer):
"""Serializer for reviews with user details."""
user_name = serializers.CharField(source='user.name', read_only=True)
class Meta:
model = Review
fields = ['id', 'user_name', 'rating', 'text', 'created_at']
read_only_fields = ['id', 'user_name', 'created_at']
class PlaceDetailSerializer(serializers.ModelSerializer):
"""Detailed serializer for a single place with all reviews."""
average_rating = serializers.SerializerMethodField()
reviews = serializers.SerializerMethodField()
class Meta:
model = Place
fields = ['id', 'name', 'address', 'average_rating', 'reviews']
read_only_fields = ['id']
def get_average_rating(self, obj):
"""Get the average rating for this place."""
return obj.average_rating
def get_reviews(self, obj):
"""
Get all reviews sorted with current user's review first,
then all others sorted by newest first.
"""
request = self.context.get('request')
if not request or not request.user.is_authenticated:
reviews = obj.reviews.all()
else:
# Get current user's review
user_review = obj.reviews.filter(user=request.user).first()
# Get all other reviews
other_reviews = obj.reviews.exclude(user=request.user).order_by('-created_at')
# Combine: user's review first, then others
if user_review:
reviews = [user_review] + list(other_reviews)
else:
reviews = list(other_reviews)
return ReviewSerializer(reviews, many=True).data
class AddReviewSerializer(serializers.Serializer):
"""Serializer for adding a review (creates place if needed)."""
place_name = serializers.CharField(max_length=255)
place_address = serializers.CharField()
rating = serializers.IntegerField(min_value=1, max_value=5)
review_text = serializers.CharField()
def validate(self, data):
"""Validate the review data."""
return data
def create(self, validated_data):
"""
Create a review and associated place if it doesn't exist.
Uses get_or_create to ensure atomic operation.
"""
user = self.context['request'].user
# Get or create the place
place, created = Place.objects.get_or_create(
name=validated_data['place_name'],
address=validated_data['place_address']
)
# Create or update the review
review, created = Review.objects.update_or_create(
user=user,
place=place,
defaults={
'rating': validated_data['rating'],
'text': validated_data['review_text']
}
)
return review