I have a post model and i have a post image model. I would like to show the images related to a post in the API, but I cannot seem to get it right.I only see the post data and not the related images.
Here are my post and post image models:
class Post(models.Model):
EV = "Everybody"
FO = "Followers"
FR = "Friends"
AUDIENCE = [
(EV, "Everybody"),
(FO, "Followers"),
(FR, "Friends"),
]
category = models.ForeignKey(Category, on_delete=models.SET_DEFAULT, default=1)
body = models.TextField("content", blank=True, null=True, max_length=5000)
slug = AutoSlugField(populate_from=["category", "created_at"])
video = models.FileField(upload_to=user_directory_path, null=True, blank=True)
can_view = models.CharField(max_length=10, choices=AUDIENCE, default=EV)
can_comment = models.CharField(max_length=10, choices=AUDIENCE, default=EV)
user = models.ForeignKey(
User, on_delete=models.CASCADE, verbose_name="user", related_name="user"
)
published = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = "post"
verbose_name_plural = "posts"
db_table = "posts"
ordering = ["created_at"]
def __str__(self):
return self.body[0:30]
def get_absolute_url(self):
return self.slug
class PostImage(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name="post")
image = models.FileField(
upload_to=post_directory_path, default="posts/default.png", null=True
)
class Meta:
db_table = "post_images"
ordering = ["post"]
def image_tag(self):
return mark_safe(
'<img src="/storage/%s" width="50" height="50" />' % (self.image)
)
image_tag.short_description = "Image"
This is the post and post images serializers:
class PostImageSerializer(serializers.ModelSerializer):
class Meta:
model = PostImage
fields = ["id", "image", "post"]
extra_kwargs = {
"post": {"required": True},
}
class PostSerializer(serializers.ModelSerializer):
images = PostImageSerializer(many=True, read_only=True, required=False)
class Meta:
model = Post
fields = [
"id",
"can_view",
"can_comment",
"category",
"body",
"images",
"video",
"user",
"published",
"created_at",
"updated_at",
]
read_only_fields = ['category', 'user']
def create(self, validated_data):
user = User.objects.get(id=self.context['request'].data.get('user'))
category = Category.objects.get(id=self.context['request'].data.get('category'))
new_post = Post.objects.create(**validated_data, category=category, user=user)
images = dict((self.context['request'].FILES).lists()).get('images', None)
if images:
for image in images:
PostImage.objects.create(
image=image, post=new_post
)
return new_post
The post gets created fine and the images related to the post as well but if I go to the API end point to look at the post's data, I see all the fields but not the nested field with the images. What am I doing wrong please? How should you nest related fields otherwise?
CodePudding user response:
A minor mistake, it's just a wrong reference. Change the field related name in models.py:
class PostImage(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name="images")
...
To add a the user profile, you can use the user
field to retrieve the profile and then exclude it from the serializer while replacing it.
There is no need to add profile
to read-only
because SerializerMethodField already has that property by default:
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = '__all__'
class PostSerializer(serializers.ModelSerializer):
images = PostImageSerializer(many=True, read_only=True, required=False)
profile = serializers.SerializerMethodField()
class Meta:
model = Post
exclude = ['user']
read_only_fields = ['category']
def get_profile(self, obj):
return UserProfileSerializer(obj.user.profile).data
def create(self, validated_data):
...
return new_post