Добавление поля добавления в Django rest framework modelserializer (write_only

#django #django-rest-framework

#django #django-rest-framework

Вопрос:

Я хочу создать mixin для дополнительных полей в Modelserializer. Пожалуйста, обратитесь к приведенному ниже коду

 class AdditionalFieldsMixin(object):
    additional_fields = dict()

    def __init__(self, *args, **kwargs):
        super(AdditionalFieldsMixin, self).__init__(*args, **kwargs)
        for field_name, field_instance in self.additional_fields.items():
            self.fields[field_name] = field_instance
        print(self.fields)

    def additional_field_before_create(self, additional_field_data):
        pass

    def additional_field_after_create(self, additional_field_data, instance):
        pass

    def additional_field_before_update(self, additional_field_data):
        pass

    def additional_field_after_update(self, additional_field_data, instance):
        pass

    def create(self, validated_data):
        additional_field_data = {}

        for additional_field in self.additional_fields.keys():
            additional_field_data[additional_field] = validated_data.pop(additional_field, None)

        self.additional_field_before_create(additional_field_data)
        instance = super(AdditionalFieldsMixin, self).create(validated_data)
        self.additional_field_after_create(additional_field_data, instance)
        return instance

    def update(self, instance, validated_data):
        additional_field_data = {}

        for additional_field in self.additional_fields.keys():
            additional_field_data[additional_field] = validated_data.pop(additional_field, None)

        self.additional_field_before_update(additional_field_data)
        instance = super(AdditionalFieldsMixin, self).update(instance, validated_data)
        self.additional_field_after_update(additional_field_data, instance)
        return instance
 

В основном классе я объявил

 additional_fields = dict(
        reference=CharField(write_only=True, allow_blank=True, allow_null=True, default=None),
    )
 

но при получении данных в режиме списка это выдает ошибку

 AssertionError: It is redundant to specify `source='reference'` on field 'CharField' in serializer 'MySerializer', because it is the same as the field name. Remove the `source` keyword argument.
 

почему это происходит?
также я отметил, что после первого запуска runserver он не выдает эту ошибку, но если я снова запрашиваю, он выдает ошибку во второй раз и так далее.

и еще один общий вопрос

как правильно добавлять поля в класс seialiser mixin? т.е. self.fields[field_name] = field_instance — правильный способ сделать это?

Ответ №1:

Вы можете это сделать, потому что, если вы используете modelerializer, вы не можете запросить

 class Name(serializers.Serializer):
    name = serializers.CharField(required=True)
    ...
    
    def create(self, validated_data):
        ...
    def update(self, instance, validated_data):
        ...
 

Ответ №2:

Дополнительные поля чтения и записи в Modelserializer

Дополнительные поля чтения и записи должны быть получены из экземпляра модели, чтобы вы могли добавить @property или def reference в модель и объявить поле в сериализаторе как

 reference = CharField(source='reference')
 

и извлеките данные поля из проверенных данных, переопределив создание обновления modelserializer.

Короче говоря, дополнительное поле для чтения и записи очень сложно реализовать в прямом коде, НО ЭТО ВОЗМОЖНО.

Дополнительные поля только для чтения в Modelserializer

Используйте SerializerMethodField , ReadOnlyField с source аргументом или аналогичный приведенный выше код с read_only=True аргументом. например

 reference = CharField(source='reference', read_only=True)
 

Дополнительные поля только для записи в Modelserializer (обязательный ответ)

Запись поля в mainserializer как

 reference = CharField(write_only=True)
 

нормально, поле будет отображаться в проверенных данных, create и update поэтому
переопределите их, откройте поле, сделайте то, что вам нужно с ним делать, сделайте super() вызов с новыми проверенными данными.

Создайте mixin, как указано в вопросе (для полей только для записи)

Оказывается, вы можете переопределить to_internal_value метод serializer и добавить к нему поля. вызывается to_internal_value , когда сериализатор сохраняет данные (создает, обновляет), поэтому вы можете переопределить его следующим образом

 def to_internal_value(self, data):
    for field_name, field_instance in self.additional_write_only_fields.items():
        self.fields[field_name] = field_instance
    return super(AdditionalWriteOnlyFieldsMixin, self).to_internal_value(data)
 

это решило бы проблему добавления многих полей только для записи в model serializer. вот почему я создал mixin следующим образом

 class AdditionalWriteOnlyFieldsMixin(object):
    additional_write_only_fields = dict()

    def to_internal_value(self, data):
        for field_name, field_instance in self.additional_write_only_fields.items():
            self.fields[field_name] = field_instance
        return super(AdditionalWriteOnlyFieldsMixin, self).to_internal_value(data)

    def additional_fields_before_create(self, additional_data):
        pass

    def additional_fields_after_create(self, additional_data, instance):
        pass

    def additional_fields_before_update(self, additional_data):
        pass

    def additional_fields_after_update(self, additional_data, instance):
        pass

    def create(self, validated_data):
        additional_data = {key: validated_data.pop(key, None) for key in self.additional_write_only_fields.keys()}
        self.additional_fields_before_create(additional_data)
        instance = super(AdditionalWriteOnlyFieldsMixin, self).create(validated_data)
        self.additional_fields_after_create(additional_data, instance)
        return instance

    def update(self, instance, validated_data):
        additional_data = {key: validated_data.pop(key, None) for key in self.additional_write_only_fields.keys()}
        self.additional_fields_before_update(additional_data)
        instance = super(AdditionalWriteOnlyFieldsMixin, self).update(instance, validated_data)
        self.additional_fields_after_update(additional_data, instance)
        return instance
 

Поэтому включите mixin в свой класс modelserializer и объявите additional_write_only_fields как dict с ключом в качестве имени поля и значением в качестве экземпляра поля и переопределите additional_fields_* функцию для реализации желаемой функциональности, например

 class MySerializer(AdditionalWriteOnlyFieldsMixin, ModelSerializer):
    additional_write_only_fields = dict(
        reference=CharField(write_only=True, allow_blank=True, allow_null=True, default=None),
    )
    
    def additional_fields_after_create(self, additional_data, instance):
        print(additional_data)
        
    class Meta:
        model=MyModel
        fields='__all__'
 

Дополнительные примечания

Вы также можете переопределить to_representation метод сериализатора для добавления полей только для чтения или создать комбинацию to_representation и to_internal_value , чтобы создать дополнительное поле для чтения и записи !. но я оставляю эту работу для другого ответа.

Ссылки