Django Rest Framework嵌套序列化器返回空列表问题求助
问题分析与修复方案
核心问题
访问/assessments返回空列表的根本原因是:提交Return数据时没有生成对应的Assessment记录,同时代码中存在关键字冲突、属性调用错误、序列化器字段不匹配等问题。
分步修复
1. 模型层修复(解决关键字冲突与属性错误)
return是Python关键字,不能作为模型字段名;同时修正Assessment中错误的属性调用逻辑:
from django.db import models import calendar from calendar import monthrange class Return(models.Model): room_type = models.CharField(max_length=50) number_of_rooms = models.PositiveSmallIntegerField() price_per_night = models.DecimalField(max_digits=10, decimal_places=2) actual_turnover = models.DecimalField(max_digits=10, decimal_places=2) created_at = models.DateField(auto_now=True) class Meta: verbose_name = 'Return' verbose_name_plural = 'Returns' def __str__(self): return f'{self.room_type}' def days_in_month(self): year = self.created_at.year month = self.created_at.month num_days = monthrange(year, month)[1] return num_days @property def potential_turnover(self) -> float: return float(self.days_in_month()) * float(self.number_of_rooms) * float(self.price_per_night) @property def total_number_of_rooms(self) -> float: # 用ORM聚合替代循环,性能更优 return Return.objects.aggregate(total=models.Sum('number_of_rooms'))['total'] or 0 @property def total_potential_turnover(self) -> float: total = 0 for obj in Return.objects.all(): total += obj.potential_turnover return total @property def gross_amount(self) -> float: # 用ORM聚合替代循环,性能更优 return Return.objects.aggregate(total=models.Sum('actual_turnover'))['total'] or 0 class Assessment(models.Model): # 替换关键字字段名,避免语法冲突 return_instance = models.ForeignKey(Return, related_name="assessments", on_delete=models.CASCADE) created_at = models.DateField(auto_now=True) class Meta: verbose_name = 'Assessment' verbose_name_plural = 'Assessments' def __str__(self): return f'{self.return_instance.room_type}' @property def gross_amount(self) -> float: # ForeignKey是单个对象,直接关联对应Return的actual_turnover return float(self.return_instance.actual_turnover) @property def total_levy_charges(self) -> float: adjustment = 0 # property不需要加括号调用 return self.gross_amount - adjustment @property def bed_night_levy_payable(self) -> float: rate_of_bed_night_levy = 0.01 return rate_of_bed_night_levy * self.total_levy_charges @property def total_monthly_bed_night_levy(self) -> float: penalty = 0 return penalty + self.bed_night_levy_payable
2. 序列化器修复(解决创建逻辑错误与字段匹配)
修正ReturnSerializer的create方法,确保创建Return时自动生成对应的Assessment;同时调整AssessmentSerializer的关联字段:
from rest_framework import serializers from .models import Return, Assessment class ReturnSerializer(serializers.ModelSerializer): class Meta: model = Return fields = ( 'id', 'room_type', 'number_of_rooms', 'total_number_of_rooms', 'price_per_night', 'potential_turnover', 'actual_turnover', 'total_potential_turnover', 'gross_amount' ) def create(self, validated_data): # 创建Return实例 return_instance = Return.objects.create(**validated_data) # 自动关联生成Assessment记录 Assessment.objects.create(return_instance=return_instance) return return_instance class AssessmentSerializer(serializers.ModelSerializer): # 关联修正后的模型字段,实现嵌套序列化 return_instance = ReturnSerializer() class Meta: model = Assessment fields = [ 'id', 'return_instance', 'created_at', 'gross_amount', 'total_levy_charges', 'bed_night_levy_payable', 'total_monthly_bed_night_levy' ]
3. 视图与URL层(无需修改)
原视图和URL配置逻辑正常,保持不变即可。
修复效果
- 提交
/returns数据时,会自动在Assessment表中生成关联记录; - 访问
/assessments时,会返回包含嵌套Return数据的完整列表,示例响应如下:
"results": [ { "id": 1, "return_instance": { "id": 1, "room_type": "Single", "number_of_rooms": 2, "total_number_of_rooms": 2, "price_per_night": "10000.00", "potential_turnover": 40000.0, "actual_turnover": "8000.00", "total_potential_turnover": 40000.0, "gross_amount": 8000.0 }, "created_at": "2024-05-20", "gross_amount": 8000.0, "total_levy_charges": 8000.0, "bed_night_levy_payable": 80.0, "total_monthly_bed_night_levy": 80.0 } ]
内容的提问来源于stack exchange,提问作者Lodyne Mark
相关产品推荐
相关产品推荐

