如何在DRF中编写与更新嵌套序列化器(无需第三方包)
Django序列化器与JWT认证问题解决方案
针对你提出的三个问题,逐个给出解决方案:
1. 不借助第三方包编写并更新UserProfile的嵌套序列化器
由于UserProfile与Account是外键关联,我们可以在UserProfileSerializer中通过嵌套序列化器实现关联操作,同时处理创建和更新逻辑:
基础实现代码(关联已有用户)
class UserProfileSerializer(ModelSerializer): # 嵌套Account序列化器,仅用于返回用户信息(前端无需传入) user = AccountSerializer(read_only=True) class Meta: model = UserProfile fields = [ "user", "address_line_1", "address_line_2", "city", "state", "country", "gender", "phone", "date_of_birth", ] def create(self, validated_data): # 从上下文获取当前登录用户(下文会讲如何传递上下文) user = self.context.get('request').user return UserProfile.objects.create(user=user, **validated_data) def update(self, instance, validated_data): # 逐个更新档案字段 instance.address_line_1 = validated_data.get('address_line_1', instance.address_line_1) instance.address_line_2 = validated_data.get('address_line_2', instance.address_line_2) instance.phone = validated_data.get('phone', instance.phone) # 其他字段同理补充 instance.save() return instance
扩展:同时创建Account和UserProfile
如果需要在一次请求中同时创建用户和档案,修改create方法即可:
def create(self, validated_data): # 提取嵌套的Account数据 user_data = validated_data.pop('user') # 调用AccountSerializer的create方法创建用户 user = AccountSerializer.create(AccountSerializer(), validated_data=user_data) # 创建关联的UserProfile return UserProfile.objects.create(user=user, **validated_data)
此时需要将user = AccountSerializer(required=True),前端需传入嵌套的user数据。
2. JWT认证时在序列化器中获取request.user
JWT认证通过后,request对象会包含当前登录用户,只需将request传入序列化器的上下文(context),即可在序列化器方法中获取:
步骤1:在视图中传递上下文
方法一:基于GenericView重写get_serializer_context
from rest_framework.generics import CreateAPIView, UpdateAPIView class UserProfileCreateView(CreateAPIView): serializer_class = UserProfileSerializer def get_serializer_context(self): context = super().get_serializer_context() # 将request传入上下文 context['request'] = self.request return context
方法二:手动实例化序列化器时传入上下文
from rest_framework import status from rest_framework.response import Response def post(self, request): serializer = UserProfileSerializer(data=request.data, context={'request': request}) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
步骤2:在序列化器中获取用户
def create(self, validated_data): # 从上下文的request中提取当前用户 user = self.context.get('request').user return UserProfile.objects.create(user=user, **validated_data)
3. 为什么设置user = AccountSerializer(required=False)才能正常运行
核心原因是你的UserProfile创建逻辑依赖上下文的当前用户,而非前端传入的user序列化数据:
- UserProfile模型的
user字段是外键,默认属于必填项。如果序列化器中user = AccountSerializer()不设置required=False,DRF会强制要求前端传入完整的user嵌套数据(如first_name、email等),否则就会抛出user: ["This field is required"]的错误。 - 而你的实际逻辑是从上下文获取当前登录用户来创建档案,根本不需要前端传user数据,所以更合理的做法是将
user设为read_only=True(只用于返回数据,不接收前端输入):
user = AccountSerializer(read_only=True)
修正后的完整模型代码(修正笔误+补充必要配置)
from django.db import models from django.contrib.auth.models import AbstractBaseUser class Account(AbstractBaseUser): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) email = models.EmailField(max_length=100, unique=True) # 继承AbstractBaseUser必须定义以下字段 USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['first_name', 'last_name'] class UserProfile(models.Model): user = models.ForeignKey(Account, on_delete=models.CASCADE) address_line_1 = models.CharField(max_length=100) address_line_2 = models.CharField(max_length=100) phone = models.IntegerField(null=True) # 补充序列化器中用到的其他字段 city = models.CharField(max_length=50) state = models.CharField(max_length=50) country = models.CharField(max_length=50) gender = models.CharField(max_length=10) date_of_birth = models.DateField(null=True)
内容的提问来源于stack exchange,提问作者Sins97
相关产品推荐
相关产品推荐

