Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to serialize using django rest_framework a ManyToManyFields with a Through Model

I have a Recipe model that holds an M2M field of an IngredientType object. This field, aka ingredient_list, uses the notorious 'through' model via an Ingredient object that adds extra data to my IngredientType. these are my classes:

class Recipe(models.Model):
    user_profile = models.ForeignKey(UserProfile, null=True, blank = True)
    name = models.CharField(max_length=200)
    photo1 = models.ImageField( upload_to = 'images/recipies', help_text="This photo will show by default")
    ingredient_list = models.ManyToManyField(IngredientType,through='Ingredient')

class Ingredient(models.Model):
    ingredient_type = models.ForeignKey(IngredientType)
    recipe = models.ForeignKey(Recipe)
    amount = models.IntegerField()
    units = models.CharField(max_length=4,choices=UNIT, 
                               default=None, null=True, blank = True)

class IngredientType(models.Model):
    name = models.CharField(max_length=200)
    plural_name = models.CharField(max_length=200)
    photo = models.ImageField( upload_to = 'images/ingredients')
    is_main = models.BooleanField()

i've tried serializing them using the rest_framework:

class IngredientTypeSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = IngredientType
        fields=('name', 'plural_name', 'photo', 'is_main')

class IngredientSerializer(serializers.HyperlinkedModelSerializer):
    ingredient_type = IngredientTypeSerializer(source = 'ingredient_type')
    amount =  serializers.Field(source='ingredient_type.amount')
    units =  serializers.Field(source='ingredient_type.units')
    recipe = serializers.Field(source='Recipe.name')
class Meta:
    model = Ingredient
    fields=('amount', 'units')

class RecipeSerializer(serializers.ModelSerializer):
    ingredient_list = IngredientSerializer(source='ingredient_list', many=True, read_only = True)
    class Meta:
        model = Recipe
        fields = ('user_profile', 'name','photo1','ingredient_list')

but when trying to run this, I get an AttributeError : 'IngredientType' object has no attribute 'ingredient_type'

clearly, when I change the line:

ingredient_list = IngredientSerializer(source='ingredient_list', many=True, read_only = True)

to:

ingredient_list = IngredientTypeSerializer(source='ingredient_list', many=True, read_only = True)

that is, change the Serializer, it works, but without fetching me the Ingredient data. i've used this link: Include intermediary (through model) in responses in Django Rest Framework as reference, but obviously it hasn't solved my problems.
Any help would be appreciated. tnx, Nitzan

like image 423
nitzanwe Avatar asked Oct 04 '13 11:10

nitzanwe


People also ask

How do you serialize an object in Django REST framework?

Creating and Using Serializers To create a basic serializer one needs to import serializers class from rest_framework and define fields for a serializer just like creating a form or model in Django.

How do you serialize a Manytomany field?

To serialize many to many field with Python Django rest framework, we can add a serializer with many set to True . to create the PostSerializer with the tag field assigned to the TagSerializer instance. We set many to true to let us serialize many to many fields.

What is serialization in Django REST framework?

Serializers allow complex data such as querysets and model instances to be converted to native Python datatypes that can then be easily rendered into JSON , XML or other content types.


1 Answers

On your Recipe model, for the ingredient_list field you have a ManyToManyField pointing to IngredientType.

On your RecipeSerializer the ingredient_list field is not using the IngredientTypeSerializer but rather the IngredientSerializer.

This is the error. (And it explains the error message — the actual model at the source doesn't have the attribute being looked for by the serializer.)

Beyond this, your naming scheme is massively confusing. "Recipe" is fine, but what you're calling "IngredientType" should probably just be "Ingredient" and then you should find a distinct name for the through table. (Maybe "RecipeIngredientDetails")

I hope that helps.

like image 79
Carlton Gibson Avatar answered Nov 15 '22 04:11

Carlton Gibson