python - 如何在 django rest 框架中使用不同的序列化器类序列化每个外键对象
问题描述
所以我想知道是否可以在 django rest 框架中用不同的序列化器序列化每个外键对象。
我的意思是:
我有我的模型
class KingdomModel(models.Model):
kingdom_name = models.CharField(max_length=32)
owner = models.OneToOneField(User, on_delete=models.CASCADE)
faction = models.CharField(max_length=10)
class CityModel(models.Model):
kingdom = models.ForeignKey(KingdomModel, on_delete=models.CASCADE, related_name="cities")
city_name = models.CharField(max_length=32)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
"""
... other fields aswell
"""
class ArmyModel(models.Model):
home_city = models.ForeignKey(CityModel, on_delete=models.CASCADE, null=True, related_name="own_troops")
current_city = models.ForeignKey(CityModel, on_delete=models.CASCADE, null=True, related_name="all_troops", blank=True)
status = models.CharField(max_length=32)
action_done_time = models.DateTimeField(default=None, null=True, blank=True)
target_city = models.ForeignKey(CityModel, on_delete=models.CASCADE, null=True, related_name="incoming_troops", default=None, blank=True)
# Shared troops
settlers = models.IntegerField(default=0)
# Gaul troops
pikemen = models.IntegerField(default=0)
swordmen = models.IntegerField(default=0)
riders = models.IntegerField(default=0)
# Roman troops
legionaries = models.IntegerField(default=0)
praetorian = models.IntegerField(default=0)
我正在尝试根据王国派系对军队进行序列化。在谈论own_troops时效果很好,因为它们总是会使用相同的序列化程序进行序列化,就像这样。
class CitySerializer(serializers.ModelSerializer):
own_troops = serializers.SerializerMethodField()
incoming_troops = serializers.SerializerMethodField()
def get_own_troops(self, city_obj):
if(KingdomModel.objects.get(owner=city_obj.owner).faction == "Gaul"):
return GaulTroopsSerializer(instance=city_obj.own_troops, context=self.context, many=True, required=False, read_only=False).data
elif(KingdomModel.objects.get(owner=city_obj.owner).faction == "Roman"):
return RomanTroopsSerializer(instance=city_obj.own_troops, context=self.context, many=True, required=False, read_only=False).data
class RomanTroopsSerializer(serializers.ModelSerializer):
class Meta:
model = ArmyModel
fields = ['id', 'home_city', 'current_city', 'target_city', 'status', 'action_done_time', 'settlers', 'legionaries', 'praetorian']
class GaulTroopsSerializer(serializers.ModelSerializer):
class Meta:
model = ArmyModel
fields = ['id', 'home_city', 'current_city', 'target_city', 'status', 'action_done_time', 'settlers', 'pikemen', 'swordmen', 'riders']
但是,如果我尝试将相同的逻辑应用于序列化incoming_troops,它将始终使用第一个序列化程序序列化列表中的所有对象。这是我根据关系中的数据用不同的序列化器序列化每个外键的绝望尝试。
def get_incoming_troops(self, city_obj):
for data in GaulTroopsSerializer(instance=city_obj.incoming_troops, context=self.context, many=True, required=False, read_only=False).data:
print(data)
home_city_obj = CityModel.objects.get(id=data['home_city'])
if(KingdomModel.objects.get(owner=home_city_obj.owner).faction == "Gaul"):
return GaulTroopsSerializer(instance=city_obj.incoming_troops, context=self.context, many=True, required=False, read_only=False).data
else:
return RomanTroopsSerializer(instance=city_obj.incoming_troops, context=self.context, many=True, required=False, read_only=False).data
class Meta:
model = CityModel
fields = ['id', 'owner', 'city_name', 'x_coordinate', 'y_coordinate', 'last_updated', 'max_warehouse_capacity', 'max_grain_silo_capacity', 'wood_ammount', 'wheat_ammount', 'stone_ammount', 'iron_ammount', 'resource_fields', 'buildings','incoming_troops', 'own_troops', 'all_troops']
read_only_fields = ['id', 'max_warehouse_capacity', 'max_grain_silo_capacity']
我知道我可以为所有不同派系的军队提供多个模型,但现在我只是想知道这在 django / drf 中是否可行?
解决方案
回答我自己的问题,因为我得到了它的工作,我所做的如下:
首先,我刮掉了多个部队序列化器。并且只有一个军队序列化器,我可以根据派系切换字段。
这是我的 ArmySerializer 现在
class ArmySerializer(serializers.ModelSerializer):
class Meta:
model = ArmyModel
fields = ['id', 'home_city', 'current_city', 'target_city', 'status', 'action_done_time']
def to_representation(self, instance):
try:
del self.fields # Clear the cache
except AttributeError:
pass
if("faction" in self.context and len(self.context['faction']) > 0):
print(self.context['faction'])
self.fields['settlers'] = serializers.IntegerField()
if(self.context['faction'][0] == "Gaul"):
self.fields['pikemen'] = serializers.IntegerField()
self.fields['swordmen'] = serializers.IntegerField()
self.fields['riders'] = serializers.IntegerField()
elif(self.context['faction'][0] == "Roman"):
self.fields['legionaries'] = serializers.IntegerField()
self.fields['praetorian'] = serializers.IntegerField()
if(len(self.context['faction']) > 1):
self.context['faction'].pop(0)
return super().to_representation(instance)
在 CitySerializer 中,我正在填充 context['faction'] 列表,如下所示:
class CitySerializer(serializers.ModelSerializer):
own_troops = serializers.SerializerMethodField()
incoming_troops = serializers.SerializerMethodField()
def get_own_troops(self, instance):
if(KingdomModel.objects.get(owner=instance.owner).faction == "Gaul"):
self.context["faction"] = ["Gaul"]
return ArmySerializer(instance=instance.own_troops, context=self.context, many=True, required=False, read_only=False).data
elif(KingdomModel.objects.get(owner=instance.owner).faction == "Roman"):
self.context["faction"] = ["Roman"]
return ArmySerializer(instance=instance.own_troops, context=self.context, many=True, required=False, read_only=False).data
def get_incoming_troops(self, city_obj):
self.context['faction'] = []
for data in ArmySerializer(instance=city_obj.incoming_troops, context=self.context, many=True, required=False, read_only=False).data:
home_city = CityModel.objects.get(id=data['home_city'])
sender_faction = KingdomModel.objects.get(owner=home_city.owner).faction
if(sender_faction == "Gaul"):
self.context['faction'] += ["Gaul"]
else:
self.context['faction'] += ["Roman"]
return ArmySerializer(instance=city_obj.incoming_troops, context=self.context, many=True, required=False, read_only=False).data
另外应该说,这在使用 POST 请求创建军队时引入了一个新问题。在 to_representation 方法中动态添加的字段默认不验证,因此它们不存在于 valid_data 中。可能有一种方法可以覆盖验证,但我现在只是从原始请求数据中获取它们,它似乎工作正常。
推荐阅读
- python - 在两个 IDS 上堆叠行列
- java - 运行“mvn clean install”时使用 springRunner.class 的测试类发生异常
- linux - 我如何修复这个像素化背景图像 qtile
- python-3.x - 在应用程序上下文之外使用类中的装饰器引发运行时错误?
- android - 房间预填充数据库未显示表中的任何数据
- amazon-web-services - AWS CodeBuild:部署代码在管道中引发 npm 错误
- php - PHP 回显变量返回一个 mysql 查询字符串
- php - 我如何使用 API Laravel 从数据库中检索
- facebook - 如何将 UTM 参数从短链接传递到长链接?
- haskell - 在 Haskell 中计算给定变化量的最小硬币数量