2015-02-11 90 views
9

我想弄清楚如何使用Django REST框架保存相關模型。 在我的應用程序中,我有一個模型Recipe與2個相關型號:RecipeIngredientRecipeStep。 A Recipe對象必須至少有3個相關的RecipeIngredient和3 RecipeStep。引進REST框架之前,我使用的Django CreateView有兩個表單集和保存過程如下(按照代碼form_valid()):Django REST框架:在ModelViewSet中保存相關模型

def save_formsets(self, recipe): 
    for f in self.get_formsets(): 
     f.instance = recipe 
     f.save() 

def save(self, form): 
    with transaction.atomic(): 
     recipe = form.save() 
     self.save_formsets(recipe) 
    return recipe 

def formsets_are_valid(self): 
     return all(f.is_valid() for f in self.get_formsets()) 

def form_valid(self, form): 
    try: 
     if self.formsets_are_valid(): 
      try: 
       return self.create_ajax_success_response(form) 
      except IntegrityError as ie: 
       return self.create_ajax_error_response(form, {'IntegrityError': ie.message}) 
    except ValidationError as ve: 
     return self.create_ajax_error_response(form, {'ValidationError': ve.message}) 
    return self.create_ajax_error_response(form) 

現在我有我的RecipeViewSet

class RecipeViewSet(ModelViewSet): 
    serializer_class = RecipeSerializer 
    queryset = Recipe.objects.all() 
    permission_classes = (RecipeModelPermission,) 

它採用RecipeSerializer

class RecipeSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = Recipe 
     fields = (
      'name', 'dish_type', 'cooking_time', 'steps', 'ingredients' 
     ) 

    ingredients = RecipeIngredientSerializer(many=True) 
    steps = RecipeStepSerializer(many=True) 

,這些都是相關的序列化:

class RecipeIngredientSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = RecipeIngredient 
     fields = ('name', 'quantity', 'unit_of_measure') 

class RecipeStepSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = RecipeStep 
     fields = ('description', 'photo') 

現在......我應該如何驗證相關的模型(RecipeIngredientRecipeStep),並將其保存在RecipeViewSetcreate()方法被調用? (is_valid()RecipeSerializer實際上忽略了嵌套關係並僅報告與主要模型Recipe相關的錯誤)。 目前我試圖覆蓋RecipeSerializer中的is_valid()方法,但不是那麼簡單......任何想法?

回答

14

我這個星期處理,有着相近的問題,我發現了,那Django的REST框架3實際上支持嵌套寫序列化(http://www.django-rest-framework.org/topics/3.0-announcement/#serializers在小節可寫嵌套的序列化。)

林不知道,如果嵌套的序列化器是可寫的是默認,所以我宣佈他們:

ingredients = RecipeIngredientSerializer(many=True, read_only=False) 
steps = RecipeStepSerializer(many=True, read_only=False) 

,你應該重寫裏面RecipeSerializer您創建methon:

class RecipeSerializer(serializers.ModelSerializer): 
    ingredients = RecipeIngredientSerializer(many=True, read_only=False) 
    steps = RecipeStepSerializer(many=True, read_only=False) 

    class Meta: 
     model = Recipe 
     fields = (
      'name', 'dish_type', 'cooking_time', 'steps', 'ingredients' 
     ) 

    def create(self, validated_data): 
     ingredients_data = validated_data.pop('ingredients') 
     steps_data = validated_data.pop('steps') 
     recipe = Recipe.objects.create(**validated_data) 
     for ingredient in ingredients_data: 
      #any ingredient logic here 
      Ingredient.objects.create(recipe=recipe, **ingredient) 
     for step in steps_data: 
      #any step logic here 
      Step.objects.create(recipe=recipe, **step) 
     return recipe 

如果這個結構Step.objects.create(recipe = recipe,** step)不起作用,也許你必須從steps_data/ingredients_data中分別選擇代表每個字段的數據。

這是鏈接到我的前面(realted)提問/回答堆棧:How to create multiple objects (related) with one request in DRF?

+0

感謝您的提示,但並非如此簡單......我在validated_data中獲得了一個空的列表成分 – daveoncode 2015-02-12 11:21:54

+0

這可能意味着,您的序列化程序不知道如何從發送給它的數據創建嵌套關係。你確定你要以正確的格式/結構發送數據嗎? – 2015-02-12 11:33:51

+0

這實際上是我的疑問:P我發送一個json,例如:'{「ingredients」:[{「name」:「名稱」,「數量」:「數量」,「unit_of_measure」:「單位」} ,...]}'......應該沒問題......或不? – daveoncode 2015-02-12 11:36:36

1

我認爲我得到了答案。

類RecetaSerializer(serializers.ModelSerializer):

ingredientes = IngredientesSerializer(many=True, partial=True) 
autor = serializers.PrimaryKeyRelatedField(queryset=User.objects.all()) 
depth = 2 

class Meta: 
    model = Receta 
    fields = ('url','pk','nombre','foto','sabias_que','ingredientes','pasos','fecha_publicacion','autor') 

def to_internal_value(self,data): 

    data["fecha_publicacion"] = timezone.now() 
    ingredientes_data = data["ingredientes"] 

    for ingrediente in ingredientes_data: 

     alimento_data = ingrediente["alimento"] 

     if Alimento.objects.filter(codigo = alimento_data['codigo']).exists(): 

      alimento = Alimento.objects.get(codigo= alimento_data['codigo'])    
      ingrediente["alimento"] = alimento 

     else: 
      alimento = Alimento(codigo = alimento_data['codigo'], nombre = alimento_data['nombre']) 
      alimento.save()     
      ingrediente["alimento"] = alimento 
    data["ingredientes"] = ingredientes_data 
    return data 

def create(self, validated_data): 

    ingredientes_data = validated_data.pop('ingredientes') 

    receta_data = validated_data 
    usuario = User.objects.get(id = validated_data["autor"]) 
    receta_data['autor'] = usuario 

    receta = Receta.objects.create(**validated_data) 


    for ingrediente in ingredientes_data: 

     alimento_data = ingrediente["alimento"] 
     ingrediente = Ingredientes(receta= receta, cantidad = ingrediente['cantidad'], unidad = ingrediente['unidad'], alimento = alimento_data) 
     ingrediente.save() 

    receta.save() 


    return receta 

重要的是要重寫to_internal_value()。我遇到了函數is_valid()的問題。因此函數to_internal_value()中的每個更改都在函數is_valid()之前is_valid()

相關問題