2016-04-01 90 views
0

這裏有一些簡單代碼片段我的問題:如何使用django-rest-framework反序列化嵌套的相關JSON數據?

的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) 

串行器:

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數據進行反序列化:

{ 
    "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." 
    } 
} 

請注意,我沒有影響力ñJSON是如何構造的,因爲我從流行的網絡遊戲「傳奇聯盟」的遊戲api中獲得了這一點。這個例子我簡化了很多,還有更多的字段和深度。

我開始反序列化只有頂層的Champion字段工作正常。比我加入ChampionSpells和ChampionPassive沒有更深層次的東西,這些厚厚的東西也工作得很好。

當我與包括SpellImageInfo到ChampionSpell反序列化添加的第二深度級i得到了以下錯誤:

---------------------------------------------------------------------- 
    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 

---------------------------------------------------------------------- 

is_valid()方法的執行返回True但是當我調用ChampionSerializer的save()方法,我得到這個錯誤。我無法弄清楚爲什麼,因爲image絕對是ChampionSpell型號通過SpellImageInfo內的ForeignKey字段。對於低一級的級別(離開SpellImageInfo),它工作正常。

有沒有人對此有解決方案或解釋?

回答

0

我不能肯定這正是你所追求的,但也許它至少是你在正確的方向開始:

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() 

輸出:

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. 
+0

謝謝您的回答。可悲的是,它並沒有幫助我很多,因爲我需要首先驗證數據(根據數據庫字段),而不是反序列化到我的django模型的對象中,以將其存儲在數據庫中。轉換爲字典是,我已經做了,然後將它傳遞給我的序列化程序。但好消息是,我解決了這個問題,現在它運作良好。我會盡快提供答案,自己回答這個問題。 – trixn