[英]How to deserialize nested related JSON Data with django-rest-framework?
Here are some simplified Code-snippets for my Problem: 这是我的问题的一些简化代码片段:
Django Model: Django模型:
class Champion(models.Model):
id = models.PositiveIntegerField(primary_key=True)
name = models.CharField(max_length=30)
# spells ([List] through ForeignKey in ChampionSpells)
# passive (through ForeignKey in ChampionPassive)
def __str__(self):
return self.name
class ChampionPassive(models.Model):
champion = models.ForeignKey(Champion, related_name='passive', related_query_name='passive')
description = models.TextField()
name = models.CharField(max_length=30)
class ChampionSpell(models.Model):
champion = models.ForeignKey(Champion, related_name='spells', related_query_name='spell')
cooldownBurn = models.CharField(max_length=40)
costBurn = models.CharField(max_length=40)
costType = models.CharField(max_length=10)
# image (through ForeignKey in ChampionImageInfo)
class SpellImageInfo(models.Model):
spell = models.ForeignKey(ChampionSpell, related_name='image', related_query_name='image')
full = models.CharField(max_length=200)
group = models.CharField(max_length=200)
Serializers: 序列化器:
class ChampionPassiveSerializer(serializers.ModelSerializer):
class Meta:
model = ChampionPassive
exclude = ('champion',)
class SpellImageInfoSerializer(serializers.ModelSerializer):
class Meta:
model = SpellImageInfo
exclude = ('spell',)
class ChampionSpellSerializer(serializers.ModelSerializer):
# after adding this field, i get a TypeError
image = SpellImageInfoSerializer()
class Meta:
model = ChampionSpell
exclude = ('champion',)
class ChampionSerializer(serializers.ModelSerializer):
passive = ChampionPassiveSerializer()
spells = ChampionSpellSerializer(many=True)
class Meta:
model = Champion
def create(self, validated_data):
spells_data = validated_data.pop('spells')
passive_data = validated_data.pop('passive')
champion = Champion.objects.create(**validated_data)
for spell_data in spells_data:
spell = ChampionSpell.objects.create(champion=champion, **spell_data)
spell_image_data = spell_data.pop('image')
SpellImageInfo.objects.create(spell=spell, **spell_image_data)
ChampionPassive.objects.create(champion=champion, **passive_data)
return champion
JSON data to be deserialized: 要反序列化的JSON数据:
{
"id": 1,
"name": "Annie",
"spells": [{
"name": "Disintegrate",
"description": "Annie hurls a Mana infused fireball, dealing damage and refunding the Mana cost if it destroys the target.",
"image": {
"full": "Disintegrate.png",
"group": "spell"
},
"cooldownBurn": "4",
"costType": "Mana",
"costBurn": "60\/65\/70\/75\/80"
}, {
"name": "Incinerate",
"description": "Annie casts a blazing cone of fire, dealing damage to all enemies in the area.",
"image": {
"full": "Incinerate.png",
"group": "spell"
},
"cooldownBurn": "8",
"costType": "Mana",
"costBurn": "70\/80\/90\/100\/110"
}],
"passive": {
"name": "Pyromania",
"description": "After casting 4 spells, Annie's next offensive spell will stun the target for a short duration."
}
}
Note, that i have no influence on how the JSON is structured since i get this from the game api from the popular online game "League of legends". 请注意,我对JSON的结构没有任何影响,因为我是从流行的在线游戏“英雄联盟”的游戏api中获得的。 I simplified it a lot for this example, there are a lot more fields and additional levels of depth.
在此示例中,我对其进行了很多简化,其中包含更多字段和更多层次的深度。
I started deserializing only the Champion fields on the top level which worked fine. 我开始只反序列化顶级的Champion字段,效果很好。 Than i added The ChampionSpells and ChampionPassive without the deeper level things inside these thick also worked fine.
比起我添加的ChampionSpells和ChampionPassive,如果没有这些较深层次的东西,它们也可以正常工作。
When i added the 2nd depth level with including the SpellImageInfo into the ChampionSpell deserialization i got the following error: 当我添加第二个深度级别并将SpellImageInfo包含到ChampionSpell反序列化中时,出现以下错误:
----------------------------------------------------------------------
File "/home/ubuntu/workspace/lolstatistics/stats/serializers.py", line 111, in create
spell = ChampionSpell.objects.create(champion=champion, **spell_data)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/manager.py", line 122, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 399, in create
obj = self.model(**kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/base.py", line 443, in __init__
raise TypeError("'%s' is an invalid keyword argument for this function" % list(kwargs)[0])
TypeError: 'image' is an invalid keyword argument for this function
----------------------------------------------------------------------
The execution of the is_valid()
method returns True
but when i call the save()
method of the ChampionSerializer, i get this error. is_valid()
方法的执行返回True
但是当我调用ChampionSerializer的save()
方法时,出现此错误。 I couldn't figure out why, because image
is definitely a field of the ChampionSpell
Model through the ForeignKey inside SpellImageInfo
. 我不知道为什么,因为通过
SpellImageInfo
内部的ForeignKey, image
绝对是ChampionSpell
模型的一个字段。 Also for one level of depth less (Leaving the SpellImageInfo out) it worked fine. 同样,对于少一层的深度(不包括SpellImageInfo),它也可以正常工作。
Has anybody a solution or an explanation for this? 有没有人对此有解决方案或解释?
I am not certain this is exactly what you are after, but maybe it is a start in the right direction for you at least: 我不确定这正是您所追求的,但是至少对于您来说,这可能是正确方向的起点:
import json
j = """{
"id": 1,
"name": "Annie",
"spells": [{
"name": "Disintegrate",
"description": "Annie hurls a Mana infused fireball, dealing damage and refunding the Mana cost if it destroys the target.",
"image": {
"full": "Disintegrate.png",
"group": "spell"
},
"cooldownBurn": "4",
"costType": "Mana",
"costBurn": "60\/65\/70\/75\/80"
}, {
"name": "Incinerate",
"description": "Annie casts a blazing cone of fire, dealing damage to all enemies in the area.",
"image": {
"full": "Incinerate.png",
"group": "spell"
},
"cooldownBurn": "8",
"costType": "Mana",
"costBurn": "70\/80\/90\/100\/110"
}],
"passive": {
"name": "Pyromania",
"description": "After casting 4 spells, Annie's next offensive spell will stun the target for a short duration."
}
}"""
class DeserializeJSON(object):
def __init__(self, j):
self.__dict__ = json.loads(j)
d = DeserializeJSON(j)
print(d.id)
print(d.name)
print()
print(d.spells[0]["name"])
print()
print(d.spells[0]["image"]["full"])
print()
print(d.passive["name"])
print()
for k, v in enumerate(d.spells):
print(k)
print(v["name"])
print(v["description"])
print()
Output: 输出:
1
Annie
Disintegrate
Disintegrate.png
Pyromania
0
Disintegrate
Annie hurls a Mana infused fireball, dealing damage and refunding the Mana cost if it destroys the target.
1
Incinerate
Annie casts a blazing cone of fire, dealing damage to all enemies in the area.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.