Как я могу сериализовать поле Many to Many с добавленными данными в Django Rest Framework, без дополнительных ключей в ответе?

Я использую Django 3.2 и Django Rest Framework 3.14.

У меня есть пользователи, которые должны иметь возможность следить за другими пользователями, как в социальных сетях. При сериализации полного пользователя я хотел бы получить список тех пользователей, которые следуют за ним, а также дополнительные данные, такие как время следования. Однако я хотел бы, чтобы ответ оставался "плоским", например, таким:

{
    "username":"admin",
    "followers":[
        {
            "username":"testuser",
            --additional user fields--
            "follow_date":"2023-02-08 01:00:02"
        },
        --additional followers--
    ],
    --additional user fields--
}

Я могу пройти "через" мою модель join только с помощью дополнительного сериализатора, и в итоге получаю следующее:

{
    "username":"admin",
    "followers":[
        {
            "user":{
                "username":"testuser",
                --additional user fields--
            },
            "follow_date":"2023-02-08 01:00:02"
        },
        --additional followers--
    ],
    --additional user fields--
}

Обратите внимание, что есть дополнительная клавиша user

"user":{
    "username":"testuser",
    --additional user fields--
},

Я не хочу, чтобы это было там!

Моя модель выглядит примерно так:

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)

Мои сериализаторы выглядят следующим образом (лишние поля обрезаны для краткости):

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']

Учитывая это, я понимаю, почему он делает то, что делает. Но я не могу найти способ пропустить дополнительный ключ user и при этом включить информацию о пользователе и follow_date.

Я пробовал играть с прокси-моделями на User, но это, похоже, не помогло. Я подозреваю, что дело не в конфигурации, хотя мне бы хотелось, чтобы это было так, и что мне нужно переопределить какую-то внутреннюю функцию. Но я не могу найти, что это может быть.

Какой лучший (и, надеюсь, самый простой!) способ достичь этого?

Один из подходов заключается в использовании поля метода сериализатора на FollowerSerializer следующим образом:

class FollowerSerializer(serializers.ModelSerializer):
    username = serializers.SerializerMethodField()

    class Meta:
        model = Follower
        fields = ['username', 'follow_date']

    def get_username(self, obj):
        return obj.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")

        # flatten the follower data with the user data
        return {
            **data,
            **user_data,
        }

Обратите внимание, что это также повлияет на FullUserSerializer.following

Вернуться на верх