1
resposta

Inner join no Django Rest Framework

Olá, boa tarde. Estou fazendo uns testes e surgiu uma dúvida. Tenho dois Models:

class StateModel(models.Model):
    Id = models.AutoField(primary_key=True)
    Name = models.CharField(max_length = 255, null=False)
    UF = models.CharField(max_length = 2, null=False)

class CityModel(models.Model):
    Id = models.AutoField(primary_key=True)
    Name = models.CharField(max_length = 255, null=False)
    State = models.ForeignKey(StateModel, on_delete=models.CASCADE)

Os seguintes serializers

class StateSerializer(serializers.ModelSerializer):
    class Meta:
        model = StateModel
        fields = '__all__'

class CitySerializer(serializers.ModelSerializer):
    State = StateSerializer(read_only=True)

    class Meta:
        model = CityModel
        fields = '__all__'

e o view

class CityViewSet(viewsets.ModelViewSet):
    queryset = CityModel.objects.all()
    serializer_class = CitySerializer

A minha intenção é fazer a requisição get e trazer os dados com o join. Isso até que está funcionando, mas se eu fizer um post passando o ID do estado para cadastrar uma nova cidade não funciona mais, pois dá erro, pois na URL de cadastro de nova cidade na rota "http://localhost:8000/city/" só aparece o campo "name" e não as opções de estado já cadastrados. Por outro lado, se eu remover a linha do join (State = StateSerializer(read_only=True)) volta a funcionar. Alguém tem alguma ideia de como fazer funcionar o join e os outros verbos continuarem funcionando por padrão?

Na imagem a seguir podem ver que não aparece mais o campo para selecionar o estado

Insira aqui a descrição dessa imagem para ajudar na acessibilidade

1 resposta

Olá Hugo, tudo bem com você?

Peço desculpas pela demora no retorno.

O problema está ocorrendo porque o serializer do CityModel está definindo o campo State como somente leitura (read-only), o que significa que o campo não é incluído quando o serializer é usado para criar ou atualizar instâncias de CityModel.

Para corrigir isso, você pode usar o parâmetro extra_kwargs no serializer do CityModel para definir o campo "State" como gravável (writable) apenas para a criação de novas instâncias de CityModel:

class CitySerializer(serializers.ModelSerializer):
    State = StateSerializer(read_only=True)

    class Meta:
        model = CityModel
        fields = '__all__'
        extra_kwargs = {'State': {'write_only': True}}

Com essa configuração, o campo "State" só será exigido na criação de novas instâncias de CityModel e não será incluído nas respostas da API.

Se você quiser permitir a atualização do campo State em instâncias existentes de CityModel, você pode criar um serializer separado para atualização e usar o parâmetro partial=True no método update() do viewset para permitir atualizações parciais:


class CityUpdateSerializer(serializers.ModelSerializer):
    class Meta:
        model = CityModel
        fields = '__all__'
        extra_kwargs = {'State': {'write_only': True}}

class CityViewSet(viewsets.ModelViewSet):
    queryset = CityModel.objects.all()
    serializer_class = CitySerializer

    def get_serializer_class(self):
        if self.action == 'update':
            return CityUpdateSerializer
        return self.serializer_class

    def update(self, request, *args, **kwargs):
        kwargs['partial'] = True
        return super().update(request, *args, **kwargs)

Com essa configuração, o serializer padrão (CitySerializer) será usado para as operações de leitura e criação, enquanto o serializer CityUpdateSerializer será usado para atualizações, permitindo que o campo State seja atualizado.

Vale ressaltar que como é um assunto externo ao curso e que não tenho acesso ao cenário completo do projeto, pode ocorrer a necessidade de realizar outros testes afim de obter o resultado esperado, mas espero que esta resposta seja um bom ponto de partida para a resolução do seu problema.

Espero ter ajudado. Continue mergulhando em conhecimento!

Abraços e bons estudos.

Caso este post tenha lhe ajudado, por favor, marcar como solucionado ✓. Bons Estudos!