如何通过Django REST Framework返回多表关联合并的序列化响应数据
Django REST Framework合并两个关联模型序列化响应的实现方法
问题原因
你之前尝试用+拼接两个序列化器的data属性报错,是因为DRF序列化器返回的data是类字典的SerializerData/OrderedDict类型,Python原生不支持字典用+运算符做拼接操作。
方案一:视图层直接合并字典(快速实现)
不需要修改现有模型、序列化器定义,仅需修改视图返回逻辑,用字典解包的方式合并两份序列化结果:
@api_view(['GET']) def getUserByIDDemo(request, uName, pWord): username = uName password = pWord userObj = authenticate(request, username=username, password=password) # Check if authentication successful if userObj is not None: login(request, userObj) currentUser = Users.objects.get(user = userObj) userializer = UserSerializer(currentUser, many = False) # 原代码查询条件错误,应该用userID匹配而非customerID customer = Customers.objects.get(userID = userializer.data['userID']) cserializer = CustomerSerializer(customer, many = False) # 字典解包合并,重复的userID字段会保留后面对象里的值,不需要可以手动pop删除 combined_data = {**userializer.data, **cserializer.data} return Response(combined_data) else: message = "Invalid username and/or password." return Response(message)
方案二:自定义联合序列化器(规范写法)
适合需要多处用到合并数据的场景,先调整Customers模型的外键配置,增加反向查询名:
class Customers(models.Model): customerID = models.AutoField(primary_key=True) # 增加related_name指定反向查询字段名,方便从Users侧查询关联的Customers记录 userID = models.ForeignKey('Users', on_delete=models.CASCADE, related_name="customer_info") occupation = models.TextField() blogger = models.BooleanField(default= False) def __str__(self): return f"ID: {self.customerID}"
新增自定义合并序列化器:
class UserWithCustomerSerializer(ModelSerializer): # 声明关联Customers表的字段,通过source指定反向查询路径 customerID = serializers.IntegerField(source='customer_info.customerID') occupation = serializers.CharField(source='customer_info.occupation') blogger = serializers.BooleanField(source='customer_info.blogger') class Meta: model = Users fields = [ 'userID', 'firstName', 'lastName', 'gender', 'country', 'city', 'phoneNumber', 'dob', 'dateJoined', 'role', 'user', 'customerID', 'occupation', 'blogger' ]
调整视图逻辑,直接使用新序列化器完成一次性序列化:
@api_view(['GET']) def getUserByIDDemo(request, uName, pWord): username = uName password = pWord userObj = authenticate(request, username=username, password=password) if userObj is not None: login(request, userObj) # select_related预加载关联数据,减少数据库查询次数 currentUser = Users.objects.select_related('customer_info').get(user = userObj) serializer = UserWithCustomerSerializer(currentUser, many=False) return Response(serializer.data) else: message = "Invalid username and/or password." return Response(message)
内容的提问来源于stack exchange,提问作者Farrukh Nadeem
相关产品推荐
相关产品推荐

