Запись только, только чтение полей в django rest framework

У меня есть такие модели:

class ModelA(models.Model):
    name = models.CharField()


class ModelB(models.Model):
    f1 = models.CharField()
    model_a = models.ForeignKey(ModelA)

сериализаторы:

class ASerializer(serializers.ModelSerializer):
    model_b_ids = serializers.CharField()
    class Meta:
        model = ModelA
        write_only_fields = ('model_b_ids',)

Просмотры:

class AView(CreateModelMixin, GenericViewSet):

    def perform_create(self, serializer): 
        model_b_ids = parse_somehow(serializer.validated_data["model_b_ids"])
        #do something...

Проблема, которую я получаю, - это "model_b_ids"

Пользователь должен отправить его при отправке почтовых данных.

Я использую его в файле perform_create для ссылки на связанные модели.

Но это не "настоящий столбец" в ModelA, поэтому, когда я пытаюсь сохранить его, возникает исключение.

Я попробовал это всплывать из validated_data, но затем снова получаю ошибку где-то, что не может прочитать model_b_ids из модели. Любая идея по правильному использованию этого поля?

Ответ 1

Исправьте меня, если я ошибаюсь, но я не думаю, что у рамки django rest есть атрибут Meta​​p >

write_only_fields

В соответствии с их docs вы устанавливаете только поля для записи в extra_kwargs

например

class UserSerializer(ModelSerializer):
    """
    ``Serializer`` for ``User`` ..
    """

    class Meta:
        model = User
        fields = ('id', 'email', 'first_name', 'last_name' ,'security_question', 'security_question_answer', 'password', 'is_active', 'is_staff')
        read_only_fields = ('is_active', 'is_staff')
        extra_kwargs = {
            'security_question': {'write_only': True},
            'security_question_answer': {'write_only': True},
            'password': {'write_only': True}
        }

Ответ 2

В соответствии с документацией Django REST Framework :

Параметр write_only_fields на ModelSerializer перенесен в PendingDeprecation и заменен более общим дополнительным_компоном

почему он рекомендовал сделать так: вы должны использовать extra_kwargs:

extra_kwargs = {'model_b_ids': {'write_only': True}}

или

 model_b_ids = serializers.IntegerField(write_only=True)

Ответ 3

Возможно, вы контролируете, что ваш ModelA имеет свойство modelb_set. В Django вы описываете отношения в одном классе модели. Django предлагает обратную связь, используя нижнюю оболочку целевой модели и суффиксируя ее с помощью _set. Таким образом, вы можете сделать:

a = ModelA.objects.get(pk=1)
a.modelb_set.all()

Это позволит получить элемент с идентификатором (или первичным ключом) 1 из ModelA и получить все связанные элементы ModelB.

Вы можете установить для related_name значение, чтобы перезаписать значение по умолчанию:

class ModelB(models.Model):
    f1 = models.CharField()
    model_a = models.ForeignKey(ModelA, related_name='model_b')

В DRF вы можете слегка адаптировать свой сериализатор:

class ASerializer(serializers.ModelSerializer):
    model_b = serializers.PrimaryKeyRelatedField(many=True, read_only=False)

    class Meta:
        model = ModelA
        write_only_fields = ('model_b',)

С serializers.CharField() вы не можете публиковать значения и записывать их в модель, потому что это не поле модели.

Попробуйте этот пример. Тинкер и эксперимент. Это должно приблизить вас к решению.

EDIT: Я не совсем уверен, как Django создает имя для обратных отношений для имен классов PascalCase. Это model_b_set для ModelB? Или это modelb_set? Вы можете попробовать и найти.

Ответ 4

Ну, вы можете переопределить метод serializer.save() на ASerializer, чтобы создать экземпляр объекта modelA, установить его атрибуты, сохранить его, а затем установить отношения с существующими объектами modelB, сохранить их и использовать для успеха. Но я думаю, что, возможно, установив, что related_name и RelatedField для сериализатора, как было предложено, будут делать то же самое... с меньшим количеством набрав.. и в целом лучше:)