Search code examples
djangodjango-rest-frameworkdjango-serializer

How to access a serializer attribute from a method with no 'attrs' argument


Im trying to access the participants attribute in my conversation serializer from inside my 'get_other_user' method. My participants attribute returns a list of user dictionaries.

However, when I run the code I get model has no attribute 'participants'. Im assuming I have to pass in a, 'attrs' argument in to the 'get_other_user' method, (one similar to the 'def validate(self, attrs) method), then use attrs.get('participants). However, I do not know how to fill in the attrs parameter when calling this method in my get_other_username method.

Any advice would be appreciates. Thanks!

class ConversationSerializer(serializers.ModelSerializer): 

    other_username = serializers.SerializerMethodField(method_name='get_other_username', read_only=True)
    other_user_email = serializers.SerializerMethodField(method_name='get_other_user_email', read_only=True)
    # latest_message = serializers.SerializerMethodField(method_name='get_latest_message', read_only=True)
    participants = UsersSerializer(many=True, read_only=True)



    class Meta:
        model = Conversation
        fields = ['conversation_id' ,'participants','other_username', 'other_user_email']

    def get_current_user_id(self):
        user_id = self.context['current_user'].id
        return user_id

     
    def get_other_user(self):
        current_user_id = self.get_current_user_id()
        for participant in self.participants:
            if participant['id'] != current_user_id:
                return participant




    def get_other_username(self, obj):
        other_user = self.get_other_user()
        return other_user['username']

    def get_other_user_email(self, obj):
        other_user = self.get_other_user()
        return other_user.email        

Solution

  • You can pass the object as a parameter to the method field function, and iterate over it. I usually use method fields with functions populating it just by using the get_{FIELD_NAME} pattern.

    class ConversationSerializer(serializers.ModelSerializer):
        other_username = serializers.SerializerMethodField(read_only=True)
        participants = UsersSerializer(many=True, read_only=True)
    
        class Meta:
            model = Conversation
            fields = [
                "participants",
                "other_username",
            ]
    
        def get_current_user_id(self):
            user_id = self.context["current_user"].id
            return user_id
    
        def get_other_username(self, obj):
            current_user_id = self.get_current_user_id()
            for participant in obj.participants.all():
                if participant.id != current_user_id:
                    return participant
    

    This will return the first user that is not the requesting user, if you can have a conversation between more than 2 people maybe you would need to do some tinkering.