Некоторые могут сказать, что возиться с request.data
- это не «правильный путь».Но если вы все еще хотите его, то лучше создать изменяемую копию QueryDict:
data = request.data.copy()
data['my_data'] = 1
rest_framework
имеет много mixins / generics / builtin-views, которые просто инициализируют сериализаторы как SerializerCls(data=request.data, instance=something_or_none, context={'request': view.request, 'view': view}
.И если вы используете один и тот же сериализатор в нескольких представлениях, то лучше сделать ваш сериализатор «умным», а не модифицировать каждое представление.
«Умный» сериализатор должен вычислять все дополнительные данные из «raw request.data
/ request
».«Частично умным» сериализаторам может потребоваться изменить представление.
Если вам просто нужно установить пользовательское значение для некоторого поля модели при сохранении, то вы можете изменить метод представления perform_update
/ perform_create
(если выGenericAPIView
-s)
def perform_update(self, serializer):
serializer.save(my_data=1)
Если вам действительно нужны эти пользовательские данные, учитываемые во время проверки: вы можете использовать контекст:
class MySerializer(...):
def validate(self, data):
if 'my_data' in self.context:
data['my_data'] = self.context['my_data']
if data.get('my_data'):
perform_some_extra_validation(data)
return data
serializer = MySerializer(data=data, context={'my_data': 1})
serializer.is_valid()
# for ModelView-s you can change context by modifying `get_serializer_context` method
Если вы можете вычислять my_data
динамическис request
или с request.user
, затем:
- Вы можете сделать это прямо в
serializer.validate
, используя контекст:
class MySerializer(...):
def validate(self, data):
if 'request' in self.context:
data['my_data'] = build_my_data_from_request(self.context['request'])
return data
serializer = MySerializer(data=data, context={'request': request})
serializer.is_valid()
# in ModelView-s serializers are already initialized with 'request' in context
- Или вы можете использовать комбинацию контекста и
default
arg для поля:
class MyDataDefault(object):
def set_context(self, serializer_field):
self.parent = serializer_field.parent
def __call__(self):
if 'request' in self.parent.context:
return build_my_data_from_request(self.parent.context['request'])
class MySerializer(...):
my_data = serializers.SomeField(default=MyDataDefault())
# if my_data should only be set during creation (not during update)
from rest_framework.serializers import CreateOnlyDefault
class AlternativeMySerializer(...):
my_data = serializers.SomeField(default=CreateOnlyDefault(MyDataDefault()))
serializer = MySerializer(data=data, context={'request': request})
serializer.is_valid()
# in ModelView-s serializers are already initialized with 'request' in context
Если вы используете ModelViewSet
или другие представления, основанные на GenericAPIView
, то get_serializer
ужеделает что-то похожее на SerializerCls(data=request.data, instance=..., context={'request': request, 'view': self})
:
def get_serializer(self, *args, **kwargs):
"""
Return the serializer instance that should be used for validating and
deserializing input, and for serializing output.
"""
serializer_class = self.get_serializer_class()
kwargs['context'] = self.get_serializer_context()
return serializer_class(*args, **kwargs)
...
def get_serializer_context(self):
"""
Extra context provided to the serializer class.
"""
return {
'request': self.request,
'format': self.format_kwarg,
'view': self
}