Создание модели и связывание существующей модели по id с помощью вложенного сериализатора - PullRequest
1 голос
/ 01 апреля 2020

Можно ли использовать вложенный сериализатор, чтобы связать объект, созданный родительским сериализатором, с существующей моделью?

У меня есть две простые модели: клиент и учетная запись. Допустим, у них обоих есть только идентификатор и имя, Учетная запись также имеет (не нулевой) внешний ключ для Клиента. Я создаю 2 сериализатора и вкладываю ClientSerializer в AccountSerializer, так как я хочу видеть данные о клиенте при просмотре учетной записи.

class ClientSerializer(serializers.ModelSerializer): 
    class Meta: 
        model = Client 
        fields = '__all__'


class AccountSerializer(serializers.ModelSerializer): 
    client = ClientSerializer(required=False)
    class Meta: 
        model = Account 
        fields = '__all__' 

Это прекрасно работает для операций чтения, но если я хотел выполнить POST чтобы создать учетную запись, могу ли я сделать это с помощью AccountSerializer в его текущем состоянии? Попытка сделать следующее:

serializer = AccountSerializer(data={
    "client_id": 1,
    "name": "new account" 
})

Я получаю ошибку {'client': [ErrorDetail(string='This field is required.', code='required')]}, хотя вложенный ClientSerializer имеет значение required=False. Если я попробую это:

serializer = AccountSerializer(data={
    "client": {"id": 1},  # Client of id 1 already exists
    "name": "new account" 
})

Тогда я получу {'client': {'name': [ErrorDetail(string='This field is required.', code='required')]}}, хотя я бы не хотел ни создавать клиента, ни редактировать его имя.

Я просто хочу создать учетную запись и связать ее с существующим клиентом (с идентификатором = 1), в общем случае c, многоразовым способом. Возможно ли это с помощью DRF без необходимости определять пользовательские логики c в методе create?

1 Ответ

1 голос
/ 01 апреля 2020

Что вы можете сделать, это изменить to_internal_value метод ClientSerializer. Что-то вроде:

class ClientSerializer(serializers.ModelSerializer): 
    class Meta: 
        model = Client 
        fields = '__all__'

    def to_internal_value(self, data):
        if isinstance(data, Client):
            return data
        elif isinstance(data, int):
            return get_object_or_404(Client, pk=data)
        elif isinstance(data, dict) and data.get('id'):
            try:
                return get_object_or_404(Client, pk=int(data.get('id')))
            except ValueError:
                pass
        raise serializers.ValidationError('Client should be an integer or client item formatted object')
...