T.BJ
T.BJ

Reputation: 99

Django Rest Framework group objects dynamically

My issue is related to Django RestFramework and how to dynamically group objects. The most similar answer I found came from Rex Salisbury here but wasn't adaptable to n number of groups:

models.py

class Product(models.Model):
    name = models.CharField(max_length=20)

class Ingredient(models.Model):
    name = models.CharField(max_length=20)

class Mix(models.Model):
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    ingredient = models.ForeignKey(Ingredient, on_delete=models.CASCADE)
    percentage = models.FloatField()

    class Meta:
        unique_together = ('product', 'ingredient')

serializer.py

class MixSerializer(serializer.ModelSerializer):
    class Meta:
        model = Mix
        fields = ('product', 'liquid', 'percentage')

views.py

class MixView(viewsets.ModelViewSet):
    queryset = Mix.objects.all()
    serializer_class = MixSerializer

This is an example of the structure I'm currently getting from the API:

[ 
    {
        "product": "White Russian",
        "ingredient": "Vodka",
        "percentage": 0.54
    },
    {
        "product": "White Russian",
        "ingredient": "Coffee Liquer",
        "percentage": 0.27
    },
    {
        "product": "White Russian",
        "ingredient": "Single Cream",
        "percentage": 0.19
    }
]   

I've been trying to group these in a way which minimises the product name repetition, something like this,

{
    "product": "White Russian",
    "ingredients": {
        "Vodka": 0.54,
        "Coffee Liquer": 0.27,
        "Single Cream": 0.19
    }
}

by following documentation for Nested Relationship but I'm no longer convinced this is the right course of action. I'm comfortable getting this data from object filters but unable to implement this alongside the serializers/views.

Upvotes: 3

Views: 529

Answers (1)

Yuri Nudelman
Yuri Nudelman

Reputation: 2943

First note, according to your example you are grouping by product, so you are not looking for a MixView but for ProductView.

What you could do:

# Serializers
class MixSerializer(serializer.ModelSerializer):
    ingredient_name = serializers.CharField(source='ingredient.name')
    class Meta:
        model = Mix
        fields = ('ingredient_name', 'percentage')

class ProductSerializer(serializer.ModelSerializer):
    ingridients = MixSerializer(many=True, read_only=True)
    class Meta:
        model = Product
        fields = ('name', 'ingridients')

# Views
class ProductView(viewsets.ModelViewSet):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer

Should give you something like:

{
    "name": "White Russian",
    "ingredients": [
        {"ingredient_name": "Vodka", "percentage" : 0.54},
        {"ingredient_name": "Coffee Liquer", "percentage" : 0.27},
        {"ingredient_name": "Single Cream", "percentage" : 0.19}
    ]
}

P.S. To make it non read only you will need to also implement create and update methods under ProductSerializer

Upvotes: 2

Related Questions