Django骑手注册接口嵌套序列化数据未正确返回问题求助
Django骑手注册字段未正确保存问题排查与解决
我在Django应用中实现骑手注册功能时,遇到嵌套序列化数据未正确返回的问题:
请求数据:
{ "email": "faruqmohammad@gmail.com", "first_name": "Faruq", "last_name": "Mohahmmad", "phone_number": "08137021976", "password": "#FaruqMohammad1234", "confirm_password": "#FaruqMohammad1234", "vehicle_registration_number": "ABJ145", "min_capacity": 20, "max_capacity": 50, "fragile_item_allowed": true, "charge_per_mile": 1000 }
响应数据:
{ "data": { "user": { "email": "mohammedfaruq@gmail.com", "first_name": "Mohammed", "last_name": "Faruq", "phone_number": "08137021976" }, "is_available": true, "vehicle_type": "TWO_WHEELER", "vehicle_registration_number": "", "min_capacity": null, "max_capacity": null, "fragile_item_allowed": true, "ratings": null, "charge_per_mile": null }, "message": "Rider registration successful" }
可见,vehicle_registration_number、min_capacity等骑手专属字段未获取请求数据,而是使用了模型默认值。
相关代码
Rider模型
class Rider(models.Model): user = models.OneToOneField( CustomUser, on_delete=models.CASCADE, related_name="rider_profile" ) vehicle_type = models.CharField(max_length=50, default="TWO_WHEELER") vehicle_registration_number = models.CharField(max_length=20, unique=True) is_available = models.BooleanField(default=True) min_capacity = models.PositiveIntegerField(null=True, blank=True) max_capacity = models.PositiveIntegerField(null=True, blank=True) fragile_item_allowed = models.BooleanField(default=True) charge_per_mile = models.DecimalField( max_digits=6, decimal_places=2, null=True, blank=True ) current_latitude = models.DecimalField( max_digits=9, decimal_places=6, null=True, blank=True ) current_longitude = models.DecimalField( max_digits=9, decimal_places=6, null=True, blank=True ) ratings = models.DecimalField(max_digits=3, decimal_places=2, null=True, blank=True) def __str__(self): return self.user.email def update_location(self, latitude, longitude): self.current_latitude = latitude self.current_longitude = longitude self.save()
序列化器
class UserSerializer(serializers.ModelSerializer): password = serializers.CharField(write_only=True, required=True) confirm_password = serializers.CharField(write_only=True, required=True) class Meta: model = CustomUser fields = [ "email", "first_name", "last_name", "phone_number", "password", "confirm_password", ] def validate_password(self, value): if len(value) < 8: raise serializers.ValidationError( "Password must be at least 8 characters long." ) if not any(char.isupper() for char in value): raise serializers.ValidationError( "Password must contain at least one uppercase character." ) special_characters = "!@#$%^&*()-_=+[]{}|;:'\",.<>/? " if not any(char in special_characters for char in value): raise serializers.ValidationError( "Password must contain at least one special character." ) if not any(char.isdigit() for char in value): raise serializers.ValidationError( "Password must contain at least one number." ) return value def validate_email(self, value): if CustomUser.objects.filter(email=value).exists(): raise serializers.ValidationError("This email is already in use.") return value def validate(self, data): password = data.get("password") confirm_password = data.get("confirm_password") if password != confirm_password: raise serializers.ValidationError("Passwords do not match.") return data def create(self, validated_data): validated_data.pop("confirm_password", None) password = validated_data.get("password") if password is None: raise serializers.ValidationError("Password cannot be empty.") self.validate_password(password) user = CustomUser.objects.create_user(**validated_data) user.set_password(password) user.save() return user class CustomUserNestedSerializer(serializers.ModelSerializer): class Meta: model = CustomUser fields = ( "email", "first_name", "last_name", "phone_number", ) class RiderSerializer(serializers.ModelSerializer): user = CustomUserNestedSerializer(read_only=True) class Meta: model = Rider fields = [ "user", "is_available", "vehicle_type", "vehicle_registration_number", "min_capacity", "max_capacity", "fragile_item_allowed", "ratings", "charge_per_mile", ]
视图
class BaseUserRegistrationView(APIView): user_model = None serializer_class = None @transaction.atomic def post(self, request, *args, **kwargs): logger.debug(f"Request_data: {request.data}") user_data = request.data user_serializer = UserSerializer(data=user_data) if user_serializer.is_valid(): user_data = user_serializer.validated_data if user_data: try: with transaction.atomic(): user = user_serializer.save() user_obj = self.user_model.objects.create(user=user) user_obj_serializer = self.serializer_class(user_obj).data if user_obj_serializer: send_verification_email(user, "registration") return Response( { "data": user_obj_serializer, "message": f"{self.user_model.__name__} registration successful", }, status=status.HTTP_201_CREATED, ) else: return Response( { "detail": "Validation error", "errors": user_serializer.errors, }, status=status.HTTP_400_BAD_REQUEST, ) except IntegrityError as e: logger.error(f"Integrity error: {e}") return Response( { "detail": "Integrity error. Please ensure the data is unique." }, status=status.HTTP_400_BAD_REQUEST, ) except Exception as e: logger.error(f"An unexpected error occurred: {e}") return Response( {"detail": "An unexpected error occurred."}, status=status.HTTP_500_INTERNAL_SERVER_ERROR, ) else: return Response( {"detail": "Validation error", "errors": user_serializer.errors}, status=status.HTTP_400_BAD_REQUEST, ) class RiderRegistrationView(BaseUserRegistrationView): user_model = Rider serializer_class = RiderSerializer
问题原因
核心问题在于创建Rider对象时未传入请求中的骑手字段数据:
在BaseUserRegistrationView的post方法中,创建Rider的代码是:
user_obj = self.user_model.objects.create(user=user)
仅传递了user关联字段,其余骑手专属字段(如vehicle_registration_number)未从request.data中提取并传入,导致Rider模型使用默认值或空值。
同时,UserSerializer仅验证和处理CustomUser的字段,不会处理Rider的字段,这些字段需要单独提取和验证。
解决方案
方案一:直接提取字段创建Rider(快速修复)
修改BaseUserRegistrationView的post方法,在创建Rider时传入请求中的骑手字段:
@transaction.atomic def post(self, request, *args, **kwargs): logger.debug(f"Request_data: {request.data}") user_data = request.data # 分离CustomUser和Rider的字段 rider_fields = [ "vehicle_registration_number", "min_capacity", "max_capacity", "fragile_item_allowed", "charge_per_mile", "vehicle_type" # 可选,若允许用户自定义车型 ] rider_data = {key: request.data.get(key) for key in rider_fields if key in request.data} user_serializer = UserSerializer(data=user_data) if user_serializer.is_valid(): user_data = user_serializer.validated_data if user_data: try: with transaction.atomic(): user = user_serializer.save() # 传入rider_data创建Rider user_obj = self.user_model.objects.create(user=user, **rider_data) user_obj_serializer = self.serializer_class(user_obj).data if user_obj_serializer: send_verification_email(user, "registration") return Response( { "data": user_obj_serializer, "message": f"{self.user_model.__name__} registration successful", }, status=status.HTTP_201_CREATED, ) # ... 其余错误处理代码不变
方案二:使用RiderSerializer验证并创建(更规范)
这种方式利用DRF序列化器的验证能力,更符合REST框架的设计:
- 修改
RiderSerializer,允许写入user字段(通过隐藏字段):
class RiderSerializer(serializers.ModelSerializer): user = CustomUserNestedSerializer(read_only=True) # 添加隐藏的user字段用于创建时关联 user_id = serializers.PrimaryKeyRelatedField( queryset=CustomUser.objects.all(), write_only=True, source="user" ) class Meta: model = Rider fields = [ "user", "user_id", "is_available", "vehicle_type", "vehicle_registration_number", "min_capacity", "max_capacity", "fragile_item_allowed", "ratings", "charge_per_mile", ]
- 修改
BaseUserRegistrationView的post方法:
@transaction.atomic def post(self, request, *args, **kwargs): logger.debug(f"Request_data: {request.data}") # 先验证并创建User user_serializer = UserSerializer(data=request.data) if not user_serializer.is_valid(): return Response( {"detail": "Validation error", "errors": user_serializer.errors}, status=status.HTTP_400_BAD_REQUEST, ) try: with transaction.atomic(): user = user_serializer.save() # 准备Rider数据,添加user关联 rider_data = request.data.copy() rider_data["user_id"] = user.id # 验证并创建Rider rider_serializer = self.serializer_class(data=rider_data) if not rider_serializer.is_valid(): raise serializers.ValidationError(rider_serializer.errors) user_obj = rider_serializer.save() send_verification_email(user, "registration") return Response( { "data": rider_serializer.data, "message": f"{self.user_model.__name__} registration successful", }, status=status.HTTP_201_CREATED, ) except IntegrityError as e: logger.error(f"Integrity error: {e}") return Response( {"detail": "Integrity error. Please ensure the data is unique."}, status=status.HTTP_400_BAD_REQUEST, ) except serializers.ValidationError as e: return Response( {"detail": "Validation error", "errors": e.detail}, status=status.HTTP_400_BAD_REQUEST, ) except Exception as e: logger.error(f"An unexpected error occurred: {e}") return Response( {"detail": "An unexpected error occurred."}, status=status.HTTP_500_INTERNAL_SERVER_ERROR, )
额外优化:清理UserSerializer的字段验证
确保UserSerializer只处理CustomUser的字段,避免意外包含Rider字段。如果需要严格验证,可以添加代码检查未知字段:
class UserSerializer(serializers.ModelSerializer): # ... 现有代码 def validate(self, data): # 检查是否有未知字段 allowed_fields = set(self.fields.keys()) input_fields = set(data.keys()) unknown_fields = input_fields - allowed_fields if unknown_fields: raise serializers.ValidationError(f"Unknown fields: {', '.join(unknown_fields)}") # ... 现有密码验证代码
验证修改效果
重新发送请求后,响应中的骑手字段应正确返回请求传入的值:
{ "data": { "user": { "email": "faruqmohammad@gmail.com", "first_name": "Faruq", "last_name": "Mohahmmad", "phone_number": "08137021976" }, "is_available": true, "vehicle_type": "TWO_WHEELER", "vehicle_registration_number": "ABJ145", "min_capacity": 20, "max_capacity": 50, "fragile_item_allowed": true, "ratings": null, "charge_per_mile": "1000.00" }, "message": "Rider registration successful" }
内容的提问来源于stack exchange,提问作者Abdulmujeeb Ahmad
相关产品推荐
相关产品推荐

