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!
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
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!
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