from django.contrib.auth import password_validation from rest_framework import serializers from .models import Follow, User class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = ["id", "username", "display_name", "bio", "avatar", "is_private", "date_joined"] read_only_fields = ["id", "date_joined"] class ProfileSerializer(UserSerializer): """UserSerializer plus the counts/relationship state a profile page needs. Kept separate from UserSerializer (used for owner/author fields all over the feed) so those hot paths don't pay for two extra COUNT queries per embedded user.""" follower_count = serializers.SerializerMethodField() following_count = serializers.SerializerMethodField() viewer_follow_id = serializers.SerializerMethodField() viewer_follow_status = serializers.SerializerMethodField() class Meta(UserSerializer.Meta): fields = UserSerializer.Meta.fields + [ "follower_count", "following_count", "viewer_follow_id", "viewer_follow_status", ] def _viewer_follow(self, obj): request = self.context.get("request") if not request or not request.user.is_authenticated or request.user.id == obj.id: return None if not hasattr(obj, "_viewer_follow_cache"): obj._viewer_follow_cache = Follow.objects.filter(follower=request.user, following=obj).first() return obj._viewer_follow_cache def get_follower_count(self, obj): return obj.follower_edges.filter(status=Follow.Status.ACCEPTED).count() def get_following_count(self, obj): return obj.following_edges.filter(status=Follow.Status.ACCEPTED).count() def get_viewer_follow_id(self, obj): follow = self._viewer_follow(obj) return follow.id if follow else None def get_viewer_follow_status(self, obj): follow = self._viewer_follow(obj) return follow.status if follow else None class RegisterSerializer(serializers.ModelSerializer): password = serializers.CharField(write_only=True) class Meta: model = User fields = ["id", "email", "username", "password", "display_name"] def validate_password(self, value): password_validation.validate_password(value) return value def create(self, validated_data): password = validated_data.pop("password") user = User(**validated_data) user.set_password(password) user.save() return user class FollowSerializer(serializers.ModelSerializer): follower = UserSerializer(read_only=True) following = UserSerializer(read_only=True) following_id = serializers.PrimaryKeyRelatedField( queryset=User.objects.all(), source="following", write_only=True ) class Meta: model = Follow fields = ["id", "follower", "following", "following_id", "status", "created_at"] read_only_fields = ["id", "follower", "status", "created_at"] def create(self, validated_data): follower = self.context["request"].user following = validated_data["following"] status = Follow.Status.PENDING if following.is_private else Follow.Status.ACCEPTED follow, _ = Follow.objects.get_or_create( follower=follower, following=following, defaults={"status": status} ) return follow