英文:
How can I serialize a Many to Many field with added data in Django Rest Framework, without extra keys in the response?
问题
I am using Django 3.2 and Django Rest Framework 3.14.
I have Users that should be able to follow other Users, like on a social networking site. When serializing a full User, I would like to get a list of those following Users, as well as additional data, such as the follow datetime. However, I would like the response to stay "flat," like this:
{
"username":"admin",
"followers":[
{
"username":"testuser",
--additional user fields--
"follow_date":"2023-02-08 01:00:02"
},
--additional followers--
],
--additional user fields--
}
I can only seem to go "through" my join model using an extra serializer, and end up with this:
{
"username":"admin",
"followers":[
{
"user":{
"username":"testuser",
--additional user fields--
},
"follow_date":"2023-02-08 01:00:02"
},
--additional followers--
],
--additional user fields--
}
Note how there is an additional user
key:
"user":{
"username":"testuser",
--additional user fields--
},
I don't want that there!
My model looks something like this:
class Follower(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.RESTRICT, related_name="followers")
follower = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.RESTRICT, related_name="following")
follow_date = models.DateTimeField(auto_now_add=True)
My serializers look like this (extra fields trimmed for brevity):
class UserSnippetSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['username']
class FollowerSerializer(serializers.ModelSerializer):
user = UserSnippetSerializer(source='follower')
class Meta:
model = Follower
fields = ['user', 'follow_date']
class FullUserSerializer(serializers.ModelSerializer):
followers = FollowerSerializer(source='user.followers', many=True)
following = FollowerSerializer(source='user.following', many=True)
class Meta:
model = Profile
fields = ['username', 'followers', 'following']
Given this, I understand why it's doing what it is. But I can't seem to find any way to skip the extra user
key, while still including both the User information AND the follow_date
.
I've tried playing around with proxy models on User, but that didn't seem to help. I suspect that this is no configuration thing, though I would like it to be, and that I need to override some internal function. But I can't seem to locate what that would be.
What's the best (and hopefully easiest!) way to accomplish this?
英文:
I am using Django 3.2 and Django Rest Framework 3.14.
I have Users that should be able to follow other Users, like on a social networking site. When serializing a full User, I would like to get a list of those following Users, as well as additional data, such as the follow datetime. However, I would like the response to stay "flat", like this:
{
"username":"admin",
"followers":[
{
"username":"testuser",
--additional user fields--
"follow_date":"2023-02-08 01:00:02"
},
--additional followers--
],
--additional user fields--
}
I can only seem to go "through" my join model using an extra serializer, and end up with this:
{
"username":"admin",
"followers":[
{
"user":{
"username":"testuser",
--additional user fields--
},
"follow_date":"2023-02-08 01:00:02"
},
--additional followers--
],
--additional user fields--
}
Note how there is an additional user
key
"user":{
"username":"testuser",
--additional user fields--
},
I don't want that there!
My model looks something like this:
class Follower(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.RESTRICT, related_name="followers")
follower = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.RESTRICT, related_name="following")
follow_date = models.DateTimeField(auto_now_add=True)
My serializers look like this (extra fields trimmed for brevity):
class UserSnippetSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['username']
class FollowerSerializer(serializers.ModelSerializer):
user = UserSnippetSerializer(source='follower')
class Meta:
model = Follower
fields = ['user', 'follow_date']
class FullUserSerializer(serializers.ModelSerializer):
followers = FollowerSerializer(source='user.followers', many=True)
following = FollowerSerializer(source='user.following', many=True)
class Meta:
model = Profile
fields = ['username', 'followers', 'following']
Given this, I understand why it's doing what it is. But I can't seem to find any way to skip the extra user
key, while still including bot the User information AND the follow_date
.
I've tried playing around with proxy models on User, but that didn't seem to help. I suspect that this is no configuration thing, though I would like it to be, and that I need to override some internal function. But I can't seem to locate what that would be.
What's the best (and hopefully easiest!) way to accomplish this?
答案1
得分: 1
一种方法是在 FollowerSerializer
上使用一个序列化方法字段,像这样:
class FollowerSerializer(serializers.ModelSerializer):
username = serializers.SerializerMethodField()
class Meta:
model = Follower
fields = ['username', 'follow_date']
def get_username(self, obj):
return obj.follower.username
或者,如果你需要显示来自用户的多个字段,你也可以像这样重写 to_representation
:
class FollowerSerializer(serializers.ModelSerializer):
user = UserSnippetSerializer(source='follower')
class Meta:
model = Follower
fields = ['user', 'follow_date']
def to_representation(self, instance):
data = super().to_representation(instance)
user_data = data.pop("user")
# 将关注者数据与用户数据展开
return {
**data,
**user_data,
}
请注意,这也会影响 FullUserSerializer.following
。
英文:
One approach is to use a serializer method field on FollowerSerializer
like this:
class FollowerSerializer(serializers.ModelSerializer):
username = serializers.SerializerMethodField()
class Meta:
model = Follower
fields = ['username', 'follow_date']
def get_username(self, obj):
return obj.follower.username
or if you have lots of fields to display from user, you can also override to_representation
like this:
class FollowerSerializer(serializers.ModelSerializer):
user = UserSnippetSerializer(source='follower')
class Meta:
model = Follower
fields = ['user', 'follow_date']
def to_representation(self, instance):
data = super().to_representation(instance)
user_data = data.pop("user")
# flatten the follower data with the user data
return {
**data,
**user_data,
}
Note that this will also affect FullUserSerializer.following
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论