DRF Serializer - Принимать поле, но не использовать его в `create` или `update`.
У меня есть модель Message
, которая имеет FileField
. Мой API принимает файлы в кодировке Base64
, чтобы их можно было отправить вместе с другими данными.
Чтобы узнать имя файла и расширение, в сериализаторе есть еще одно поле attachment_filename
, которое не является полем модели. Оно используется внутри Base64Field
.
Я хочу иметь возможность проверить, есть ли оба attachment_filename
, attachment
или ни одного из них.
Проблема в том, что если attachment_filename
только для чтения, то его нет в validate
- data
переменной.
С другой стороны, если это required=False
, allow_null=True
, сериализатор выдает ошибку при создании сообщения:
TypeError: ChatMessage() got an unexpected keyword argument 'attachment_filename'
Код:
class Base64File(Base64FileField): # todo make accept a list of extensions (finite eg. pdf, xlsx, csv, txt )
ALLOWED_TYPES = ['pdf', 'xlsx', 'png', 'jpg', 'jpeg', 'docx', 'doc', 'zip']
def get_file_extension(self, filename, decoded_file):
extension = self.get_full_name().split('.')[-1]
return extension
def get_file_name(self, decoded_file):
attachment_filename = self.get_full_name()
return '.'.join(attachment_filename.split('.')[:-1])
def get_full_name(self):
return self.context['request'].data['attachment_filename'] # todo validate name
class ChatMessageSerializer(serializers.ModelSerializer):
attachment = Base64File(required=False)
attachment_filename = serializers.CharField(required=False, allow_null=True)
class Meta:
model = ChatMessage
fields = '__all__'
def validate(self, data):
"""
Validation of start and end date.
"""
attachment = data.get('attachment')
attachment_filename = data.get('attachment_filename')
if bool(attachment) ^ bool(attachment_filename):
raise serializers.ValidationError("Either none or both 'attachment' and 'attachment_filename' must be present")
# del data['attachment_filename'] # works but dirty
return data
Как заставить его работать?
EDIT
Мне удалось заставить его работать, добавив
del data['attachment_filename']
перед возвратом метода validate
, но это кажется слишком "грязным".
Вы должны обработать это поведение в методе serializer.save
, например, вы можете вывести его из validated_data
вот так:
def save(self, **kwargs):
self.validated_data.pop("attachment_filename")
return super().save(**kwargs)