简体   繁体   中英

How to deal with nested serializer fields in Django Rest Framework?

I have nested serializer (AmountSerializer). I need a field meal_name in one ViewSet. But when this field is nested, I don't need it to be seen in endpoint(in MealSerializer). How to exclude field from nested serializer when is it actually nested? models.py:

class MealType(models.Model):
    name = models.TextField()

    def __str__(self):
        return self.name

class Ingredient(models.Model):
    name = models.TextField()
    
    def __str__(self):
        return self.name

class Meal(models.Model):
    name = models.TextField()
    type = models.ForeignKey(MealType, on_delete=models.CASCADE, default=None)
    recipe = models.TextField()
    photo = models.ImageField(null=True, height_field=None, width_field=None, max_length=None,upload_to='media/')
    ingredients = models.ManyToManyField(Ingredient)

    def __str__(self):
        return self.name    

class IngredientAmount(models.Model):
    ingredient_name = models.ForeignKey(Ingredient, on_delete=models.CASCADE, default=None)
    amount = models.FloatField(default=None)
    meal = models.ForeignKey(Meal, on_delete=models.CASCADE, default=None, related_name='meal_id')

    class Meta:
        ordering = ['meal']

    def __str__(self):
        return self.ingredient_name

serializers.py:

class AmountSerializer(serializers.ModelSerializer):
    ingredient_name= serializers.ReadOnlyField(source='ingredient_name.name')
    -->#meal_name = serializers.ReadOnlyField(source='meal.name')
       #I CAN'T use ReadOnlyField( #with write_only=True)
       #i trired use PrimaryKeyRelatedField
       # butgot  AssertionError: Relational field must provide a `queryset` argument, override `get_queryset`, or set read_only=`True`.
    class Meta:
        model = IngredientAmount    
        fields = ('ingredient_name','amount','meal_name')

class MealSerializer(serializers.ModelSerializer):
    type_name= serializers.ReadOnlyField(source='type.name')
    ingredients = serializers.SlugRelatedField(read_only=True, slug_field='name', many=True)   
    amount = AmountSerializer(read_only=True,  many=True,source='meal_id')
    
    class Meta:
        model = Meal
        fields = ('id', 'name', 'type_name', 'recipe', 'photo', 'ingredients','amount')

I'd rather use a trick to exclude some of the fields that are not needed in certain situations. You can inherit your serializer from ExcludeFieldsModelSerializer , and exclude any fields that you want so that the serializer will not serialize that field.

class ExcludeFieldsModelSerializer(serializers.ModelSerializer):
    """
    A ModelSerializer that takes an additional `exclude_fields` argument that
    controls which fields should be excluded from the serializer.
    Plagiarised from https://www.django-rest-framework.org/api-guide/serializers/#dynamically-modifying-fields
    """

    def __init__(self, *args, **kwargs):
        # Don't pass the 'exclude_fields' arg up to the superclass
        exclude_fields = kwargs.pop('exclude_fields', None)

        # Instantiate the superclass normally
        super(ExcludeFieldsModelSerializer, self).__init__(*args, **kwargs)

        if exclude_fields is not None:
            # Drop any fields that are specified in the `exclude_fields` argument.
            drop = set(exclude_fields)
            for field_name in drop:
                self.fields.pop(field_name)


class AmountSerializer(ExcludeFieldsModelSerializer):
    ingredient_name= serializers.ReadOnlyField(source='ingredient_name.name')
    meal_name = serializers.CharField(read_only=True, source='meal.name')


    class Meta:
        model = IngredientAmount    
        fields = ('ingredient_name','amount','meal_name')


class MealSerializer(serializers.ModelSerializer):
    type_name= serializers.ReadOnlyField(source='type.name')
    ingredients = serializers.SlugRelatedField(read_only=True, slug_field='name', many=True)   
    amount = AmountSerializer(read_only=True,  many=True, source='meal_id', exclude_fields={'meal_name'})
    
    class Meta:
        model = Meal
        fields = ('id', 'name', 'type_name', 'recipe', 'photo', 'ingredients','amount')

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM