Filter Django rest framework get request by foreign key (MultipleObjectsReturned)

Question:

I have a database table called Supplier that has a foreign key of User, each User has their own Suppliers. I got the get request working so that it returns all Suppliers in the entire table, but I can not find a way to filter it so I only receive the Suppliers associated with the User requested.

I am accessing this request by this URL:
http://localhost:8000/pm/getsuppliers/primary-key-of-user/

models.py:

class UserProfile(models.Model):
    user = models.OneToOneField(User,on_delete=models.CASCADE)
    bio = models.CharField(max_length=200)
    email = models.CharField(max_length=200)

class Supplier(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    name = models.CharField(max_length=200)
    phone = models.IntegerField()
    email = models.EmailField(max_length=200)

views.py:

class getsuppliers(viewsets.ModelViewSet):
    queryset = Supplier.objects.all()
    serializer_class = GetSuppliersSerializer
    lookup_field = 'user'

serializers.py:

class GetSuppliersSerializer(serializers.ModelSerializer):
    class Meta:
        model=Supplier
        fields=['pk','user','name','email','phone']

The error I am receiving:

ERROR: pm.models.Supplier.MultipleObjectsReturned: get() returned more than one Supplier -- it returned 10!

I have done some searching on this error and they are saying to use .filter instead of .all in the view, but I am not sure how to make it return ALL Suppliers for the requested User, this seems like it would only return 1. Maybe I am wrong, hopefully someone has an easy solution!

Asked By: kbessemer

||

Answers:

You’ll have to set the serializer’s model (inside Meta) to User, and add in a supplier_set field:

class GetUserSuppliersSerializer(serializers.ModelSerializer):
    supplier_set = SupplierSerializer(read_only=True, many=True)
    class Meta:
        model = User
        fields = ['supplier_set']

class SuppliersSerializer(serializers.ModelSerializer):
    class Meta:
        model = Supplier
        fields = ['pk','user','name','email','phone']

And also change the viewset queryset to get users.

Edit:
To answer the question in the comment, there are a few different ways to do that based on what you need, one way is to add a to_representation method in your GetUserSuppliersSerializer as such:

    def to_representation(self, instance):
        response = super().to_representation(instance)
        response["supplier_set"] = sorted(response["supplier_set"], key=lambda x: x["pk"])
        return response
Answered By: anthony2261