I want to return a nested representation of Customer
with Image
objects, where a Customer
can have many Images
.
Currently, the GET request returns a list of ALL images from the Image
queryset for each Customer
object as shown below.
How can I show only related Image
(s) for each Customer
object in a list instead?
# The 'images' field currently returns all images rather than related images to the customer id.
[
{
'id': 1,
'name': 'John Doe',
'images': [
{'id': 1, 'name': 'foo.jpg', 'customer': 1},
{'id': 2, 'name': 'bar.jpg', 'customer': 2},
{'id': 3, 'name': 'foobar.jpg', 'customer': 3},
...
]
},
{
'id': 2,
'name': 'Jane Doe',
'images': [
{'id': 1, 'name': 'foo.jpg', 'customer': 1},
{'id': 2, 'name': 'bar.jpg', 'customer': 2},
{'id': 3, 'name': 'foobar.jpg', 'customer': 3},
...
]
},
...
]
This is my current setup
Example Models
class Customer(models.Model):
name = models.CharField()
class Image(models.Model):
name = models.CharField()
customer = models.ForeignKey(
Customer, on_delete=models.CASCADE)
Example Serializers
class CustomerSerializer(serializers.ModelSerializer):
# My Customer nested relationship is expressed using ImageSerializer as a field
images = ImageSerializer(many=True)
class Meta:
model = Customer
fields = ('id', 'name', 'images')
read_only_fields = ('id',)
class ImageSerializer(serializers.ModelSerializer):
class Meta:
model = Image
fields = '__all__'
read_only_fields = ('id',)
Please let me know if my question is unclear and I will update my question. Thank you.
You need to use the related name as the field for the reverse foreign key.
In your case this would be;
class CustomerSerializer(serializers.ModelSerializer):
class Meta:
model = Customer
fields = ('id', 'name', 'image_set')
read_only_fields = ('id',)
Consider it like a reverse FK query - Customer.objects.first().image_set.all()
DRF Docs on this are here; Reverse Relations
Django docs on reversing relationships are here
Using the _set
reverse lookup like this is the django default. It's possible that you may add your own related_name
to a relationship.
An example from the django docs;
# Declare the ForeignKey with related_query_name
class Tag(models.Model):
article = models.ForeignKey(
Article,
on_delete=models.CASCADE,
related_name="tags",
related_query_name="tag",
)
name = models.CharField(max_length=255)
# That's now the name of the reverse filter
Article.objects.filter(tag__name="important")
For your example you might add something like;
class Image(models.Model):
name = models.CharField()
customer = models.ForeignKey(
Customer,
on_delete=models.CASCADE,
related_name="images"
)
The django default of Customer.image_set
will still work, but you can then do Customer.images.all()
because you've defined that related_name
for the relationship.