33👍
image = ImageSerializer(many=True, read_only=True, source='image_set')
or
image_set = ImageSerializer(many=True, read_only=True) # use image_set in fields list too.
Let’s say you have a Gallery
object similar to this:
g = Gallery.objects.get(pk=1)
Now the queryset for all the images related the given Galley
object will be:
Image.objects.filter(gallery_id=g) # g is the gallery object
In Django we can simplify it as:
g.image_set # same as Image.objects.filter(gallery_id=g)
Now the thing is where does this magical image_set
comes from. In Django ORM if you can use related_name in model’s ForeignKey to query related objects, like this:
gallery_id = models.ForeignKey(Gallery, on_delete=models.CASCADE, related_name='something')
# if you do this in your models.py then to get all images of a gallery you will now do:
g.something
But since you didn’t specified related_name
in the ForeginKey
it defaults to model name all lowercase + _set
, therefore in this case: image_set
.
Here is a link to docs.
If you specify two ForeignKey to same model from a model django will ask you to add related_name
too (when making migrations), as it can default related name for one fields only.
This is called reverse_relationship. forward_relationship
will be when you do something like this:
img = Image.objects.get(pk=1)
img.gallery_id # get the gallery object related to the image
This is quite straightforward as gallery_id
is a field in your model.
Also side note don’t name your ForeignKey fields with a trailing _id
, it’s misleading. img.gallery_id
is not the id of the Gallery it’s the whole Gallery object. Django saves Related fields with a trailing id in the database, so in your case the column name in your database will be gallery_id_id
(most likely, might have been changed in newer version).
When querying if your field name is gallery_id
:
img.gallery_id # the gallery object
img.gallery_id.id # actual id of the gallery
img.gallery_id_id # actual id of the gallery
But if you name your field just gallery
:
img.gallery # the gallery object
img.gallery.id # actual id of the gallery
img.gallery_id # actual id of the gallery
Which is a lot more clear.
So now you know why image_set
is an attribute of your model class. And drf looks for model attributes in field names, so you either have your field name same the attribute(image_set
) or specify the attribute using the source
argument of the serializer.
5👍
For things to work, you need to specify where Serializer should take data, using source keyword
In your case, this should do the trick.
class GallerySerializer(serializers.HyperlinkedModelSerializer):
image = ImageSerializer(source="image_set", many=True, read_only=True)
def validate(self, data):
# Check if user id is equal object id before creation or if SuperUser
request = self.context.get("request")
if request.user.id != data["author"].id and request.user.is_superuser is not True:
raise ValidationError("Unauthorized User Post")
return data
class Meta:
model = Gallery
fields = ["title", "author", "created_on", "modified_on", "image", "id"]
In the case where you used “related_name” in your FK declaration, you should use this reverse related name.
As you expected many Image
instance, I strongly suggest you name your field images
instead of image
I also suggest you have a look on permission instead of using getting your logic into your Serializers.