1

I am trying to pass a variable from my view to the serializer via context. The Serializer should be able to get the context variable and use it in a field that contains a nested serializer.

Since the nested serializer field cannot be read_only, I cannot use serializerMethodField.

This is how I pass the context to the serializer:

class MyListCreateAPIView(generics.ListCreateAPIView):
    
    # [...]

    def get_serializer_context(self):
        return {
            'request': self.request,
            'format': self.format_kwarg,
            'view': self,
            'asTime': '2021-02-04 16:40:00',   # <-- This is my context variable
        }

This is my serializer:

class MySerializer(serialisers.ModelSerializer):
    child = MyChildSerializer(read_only=False, asTime= ??) # <-- here I want to pass the context variable

    class Meta:
         model = MyModel
         fields = '__all__'

I know that I can access the context variable with self.context.get('asTime') but I can't access self in MySerializer attributes (child). How do I do it?

Fabio Magarelli
  • 1,031
  • 4
  • 14
  • 47
  • 1
    Why do you need to pass it as a property of `MyChildSerializer`? The thing you're asking is impossible as the serializer will already be defined by the time you even create an instance of the parent and thus your context. In your child serializer instance you can just access the context as well and get the value of `asTime` as needed. Try to ask what problem you're trying to solve instead. – Glenn D.J. Feb 07 '21 at 12:52
  • Ok but then how do I pass the context to the nested serializer `MyChildSerializer` from the parent `MySerializer`? – Fabio Magarelli Feb 07 '21 at 12:55
  • 2
    You don't have to. The context is the same for all serializers in the hierarchy. – Glenn D.J. Feb 07 '21 at 12:55
  • Oh I didn't know that, let me try and I'll get back to you :D – Fabio Magarelli Feb 07 '21 at 12:56

1 Answers1

3

You could update context of the child on init:

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)        
    self.fields['child'].context.update(self.context)

or you could catch it in for instance to_representation as:

 self.parent.context["asTime"]
iklinac
  • 14,944
  • 4
  • 28
  • 30
  • The child normally already has the context from its parent. It's only in exceptional cases that this doesn't happen but that doesn't apply to OP I believe. – Glenn D.J. Feb 07 '21 at 14:13
  • 1
    I have upvoted your comment prior, placed it here if OP does for instance use context in nested serializer \__init__ method. It was interesting to me to work it out, but I agree that normally context should be available during serialization/deserialization – iklinac Feb 07 '21 at 14:27
  • 1
    Yeah after you posted your answer I also Googled a bit and found this question: https://stackoverflow.com/questions/30560470/context-in-nested-serializers-django-rest-framework where someone actually posted a similar answer as yours here. Interesting thread. – Glenn D.J. Feb 07 '21 at 14:35
  • eh, now you made me wonder why ListField behaves like that, digging time -> https://github.com/encode/django-rest-framework/blob/master/rest_framework/fields.py#L1622 – iklinac Feb 07 '21 at 14:47