django - instalar - pip3 install rest_framework
contexto en serializadores anidados Django resto framework (2)
Si tengo un serializador anidado:
class ChildSerializer(ModelSerializer):
class Meta:
fields = (''c_name'', )
model = Child
class ParentSerializer(ModelSerializer):
child = ChildSerializer(many=True, read_only=True)
class Meta:
model = Parent
fields = (''p_name'', ''child'')
Y quiero acceder al contexto en el serializador anidado, ¿cómo puedo hacer eso? Por lo que puedo decir, el contexto no se pasa al Niño.
Quiero poder implementar un modelo de permiso por usuario en los campos, para eso he anulado el método get_fields () del ModelSerializer:
def get_fields(self):
fields = super().get_fields()
....
for f in fields:
if has_rights(self.context[''request''].user, f, "read"):
ret_val[f] = fields[f]
....
return ret_val
Lo que funciona para los serializadores normales, pero el contexto, y por lo tanto la solicitud y el usuario no están disponibles cuando el hijo anidado se pasa a get_fields (). ¿Cómo accedo al contexto cuando el serializador está anidado?
Ok he encontrado una solución de trabajo. Reemplacé la asignación de ChildSerializer en la clase Parent con un SerializerMethodField que agrega el contexto. Esto se pasa luego al método get_fields en mi CustomModelSerializer:
class ChildSerializer(CustomModelSerializer):
class Meta:
fields = (''c_name'', )
model = Child
class ParentSerializer(CustomModelSerializer):
child = serializers.SerializerMethodField(''get_child_serializer'')
class Meta:
model = Parent
fields = (''p_name'', ''child'')
def get_child_serializer(self, obj):
serializer_context = {''request'': self.context.get(''request'') }
children = Child.objects.all().filter(parent=obj)
serializer = ChildSerializer(children, many=True, context=serializer_context)
return serializer.data
y en mi CustomModelSerializer:
class CustomModelSerializer(rest_serializer_classes.HyperlinkedModelSerializer):
def __init__(self, *args, **kwargs):
"""
Make sure a user is coupled to the serializer (needed for permissions)
"""
super().__init__(*args, **kwargs)
if not self.context:
self._context = getattr(self.Meta, ''context'', {})
try:
self.user = self.context[''request''].user
except KeyError:
self.user = None
def get_fields(self):
ret = OrderedDict()
if not self.user:
print("No user associated with object")
return ret
fields = super().get_fields()
# Bypass permission if superuser
if self.user.is_superuser:
return fields
for f in fields:
if has_right(self.user, self.Meta.model.__name__.lower(), f, "read"):
ret[f] = fields[f]
return ret
Esto parece funcionar bien, y los campos del niño se descartan en el serializador cuando revoco los derechos de lectura en Child.c_name o en Parent.child
Puedes usar serialziers.ListField
en serialziers.ListField
lugar. ListField
pasa el contexto automáticamente a su hijo. Entonces, aquí está tu código
class ChildSerializer(ModelSerializer):
class Meta:
fields = (''c_name'', )
model = Child
class ParentSerializer(ModelSerializer):
child = serializers.ListField(read_only=True, child=ChildSerializer())
class Meta:
model = Parent
fields = (''p_name'', ''child'')