I have a Post model:
class Post(models.Model):
profile = models.ForeignKey(Profile, related_name="posts", on_delete=CASCADE)
project = models.ForeignKey(Project, related_name="posts", on_delete=CASCADE)
title = models.CharField(verbose_name="Title", max_length=150)
body = models.TextField(verbose_name="Content", max_length=1300)
image_url = models.URLField(max_length=256, null=True, blank=True)
liked_by = models.ManyToManyField(Profile, related_name="post_likes")
date_published = models.DateTimeField(auto_now_add=True, verbose_name="Date published")
date_modified = models.DateTimeField(auto_now=True, verbose_name="Date modified")
is_active = models.BooleanField(verbose_name="Active", default=True)
tags = TaggableManager(blank=True, related_name="posts")
objects = models.Manager()
It has a "liked_by" M2M relations to track profiles liked a post.
The goal is to get a Post object with given ID and attach a data of profiles liked this post (id, username, photo).
For this moment my query is :
post = Post.objects.filter(pk=post_pk)
.select_related("profile", "project")
.prefetch_related("liked_by")
.annotate(comments_count=Count("comments"),
likes_count=Count("liked_by"),
users_liked=ArrayAgg("liked_by"))
.first()
Later it packed to DTO (Dataclass), serializes and responses for API call.
DTO Class:
@dataclass(frozen=True)
class PostDetailDTO:
id: str | int
profile_id: str | int
project_id: str | int
title: str
body: str
image_url: str
tags: Set[str]
date_published: datetime | None
likes_count: int
comments_count: int
users_liked: List[dict] | None = None
is_active: bool = True
Serializer:
class PostDetailDTOSerializer(serializers.Serializer):
id = serializers.IntegerField(required=False, read_only=True)
profile_id = serializers.IntegerField(read_only=True)
project_id = serializers.IntegerField(read_only=True)
title = serializers.CharField(max_length=150, read_only=True)
body = serializers.CharField(max_length=1300, read_only=True)
image_url = serializers.URLField(read_only=True)
tags = serializers.ListSerializer(child=serializers.CharField(), read_only=True)
date_published = serializers.DateTimeField(read_only=True)
users_liked = serializers.ListSerializer(child=serializers.CharField(), read_only=True)
likes_count = serializers.IntegerField(read_only=True)
comments_count = serializers.IntegerField(read_only=True)
is_active = serializers.BooleanField(read_only=True)
Example of API response for this query:
{
"post": {
"id": 25,
"profile_id": 2,
"project_id": 1,
"title": "STATUS TEST",
"body": "testing filtering",
"image_url": null,
"tags": [],
"date_published": "2023-07-06T12:44:37.134234Z",
"users_liked": [
"2",
"4"
],
"likes_count": 2,
"comments_count": 0,
"is_active": false
}
}
The question is : how to make it display profile data in format [{"id": 10, "username": "hello_world", "photo": "www.url.com}, {"id":20, "username": "my_username", "photo": "www.another.com"}]
instead of just ID?
Probably there is a way through dataclass modifications by using "for in"
through "liked_by"
field but I’m looking if there is more easier way to perform it within Database/ORM. Database in use – PostgreSQL.
UPDATE:
Updated with ProfileDTO and Serializer.
ProfileDTO:
@dataclass(frozen=True)
class ProfileDTO:
id: int | None
first_name: str
last_name: str
username: str
linkedin_url: str
about: str
photo: str
rating: float
cv_file: str
# subscripted_projects: ProjectDTO
role_id: int
specialization_id: int
tools: list[ToolDTO]
Profile serializer:
class ProfileDTOSerializer(serializers.Serializer):
id = serializers.IntegerField
first_name = serializers.CharField()
last_name = serializers.CharField()
username = serializers.CharField()
linkedin_url = serializers.URLField()
photo = serializers.ImageField()
about = serializers.CharField()
rating = serializers.FloatField()
cv_file = serializers.FileField()
role_id = serializers.IntegerField()
specialization_id = serializers.IntegerField()
tools = serializers.PrimaryKeyRelatedField(queryset=Tools.objects.all(), many=True)
2
Answers
Thanks to @Geilmaker for pointing on some django feature regarding serialization of a outcome data I found a solution with a third party lib. As I use a Dataclass (DTO) to transfer data to API (and vise versa) I found usefull an "auto-dataclass" lib which maps the query object(s) to existing dataclass (model object and dataclass fields names must match). Then I just used a relataion model's serializer as a field of my model's serializer and I got whole relation object data nested in my model's object as well.
Do I get it right, that you query the posts successfully, use a serializer to get the json
and now you just want the
section instead looking like
If that is correct, you just need to adjust your serializer for the posts.
You need to have a serializer for your User model, that is serializing the model to
{"id": 2, "username": "hello_world", "photo": "www.url.com"}
. If you have that Serializer (e.g.UserSerializer
), you can adjust yourPostSerializer
like followed:Let me know if that helped, if you need more assistance or if this is not at all what you asked about! 🙂