Hey there! I am new to DRF and right now I'm working on a project with DRF + EmberJS. It is working perfectly to show data.
The next step is to POST data and I am facing some issues that I couldn't solve by myself. Let me show you:
I have this model with lots of relationships:
---------------------------------------------------------------------------------------------------------------
class Propriedade(models.Model):
nome = models.CharField(max_length=500)
tipo = models.ForeignKey(
TipoPropriedade, on_delete=models.CASCADE, null=True)
estrelas = models.IntegerField()
distancia_centro = models.FloatField()
endereco = models.ForeignKey(
'enderecos.Endereco', on_delete=models.CASCADE)
proprietario = models.ForeignKey(
'usuarios.Usuario', on_delete=models.CASCADE)
estacionamentos = models.ManyToManyField(Estacionamento, blank=True)
recepcao = models.ForeignKey(TipoRecepcao, on_delete=models.CASCADE)
comodidades = models.ManyToManyField(ComodidadePropriedade, blank=True)
---------------------------------------------------------------------------------------------------------------
That's the serializer:
---------------------------------------------------------------------------------------------------------------
class PropriedadeSerializer(WritableNestedModelSerializer):
tipo = serializers.PrimaryKeyRelatedField(queryset=TipoPropriedade.objects.all())
endereco = serializers.PrimaryKeyRelatedField(queryset=Endereco.objects.all())
proprietario = serializers.PrimaryKeyRelatedField(queryset=Usuario.objects.all())
estacionamentos = serializers.PrimaryKeyRelatedField(many=True, queryset=Estacionamento.objects.all())
recepcao = serializers.PrimaryKeyRelatedField(queryset=TipoRecepcao.objects.all())
comodidades = serializers.PrimaryKeyRelatedField(many=True, queryset=ComodidadePropriedade.objects.all())
class Meta:
model = Propriedade
fields = '__all__'
class Meta:
ordering = ['id']
def __str__(self):
return "%s" % (self.nome)
---------------------------------------------------------------------------------------------------------------
That's the ViewSet:
---------------------------------------------------------------------------------------------------------------
class PropriedadeViewSet(viewsets.ModelViewSet):
queryset = Propriedade.objects.all()
serializer_class = PropriedadeSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
resource_name = 'propriedades'
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
print(request.data)
try:
serializer.is_valid(raise_exception=True)
try:
nova_propriedade = serializer.save()
print(nova_propriedade)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
except:
print("Erro ao salvar")
except:
print(serializer.errors)
return Response(status=status.HTTP_400_BAD_REQUEST)
---------------------------------------------------------------------------------------------------------------
And that's what I am getting from the client (EmberJS):
---------------------------------------------------------------------------------------------------------------
{'nome': 'Hotel AZ', 'estrelas': 3, 'distancia_centro': '12', 'proprietario': {'type': 'usuarios', 'id': '3'}, 'tipo': {'type': 'tipos-propriedade', 'id': '1'}, 'recepcao': {'type': 'tipos-recepcao', 'id': '3'}, 'comodidades': [{'type': 'tipos-comodidades-propriedade', 'id': '4'}, {'type': 'tipos-comodidades-propriedade', 'id': '2'}], 'endereco': {'type': 'enderecos', 'id': '32'}}
---------------------------------------------------------------------------------------------------------------
When I try to validate the serializer I get this error message:
---------------------------------------------------------------------------------------------------------------
{'tipo': [ErrorDetail(string='Incorrect type. Expected pk value, received dict.', code='incorrect_type')], 'endereco': [ErrorDetail(string='Incorrect type. Expected pk value, received dict.', code='incorrect_type')], 'proprietario': [ErrorDetail(string='Incorrect type. Expected pk value, received dict.', code='incorrect_type')], 'estacionamentos': [ErrorDetail(string='Incorrect type. Expected pk value, received dict.', code='incorrect_type')], 'recepcao': [ErrorDetail(string='Incorrect type. Expected pk value, received dict.', code='incorrect_type')], 'comodidades': [ErrorDetail(string='Incorrect type. Expected pk value, received dict.', code='incorrect_type')]}
---------------------------------------------------------------------------------------------------------------
I get that it's expecting the pk instead of a dictionary with the values. But I am not sure how to get this working. I prefer to change things on the backend instead of making these changes on the frontend.
I tried to change the fields to SlugRelatedField:
---------------------------------------------------------------------------------------------------------------
class PropriedadeSerializer(serializers.ModelSerializer):
tipo = serializers.SlugRelatedField(queryset=TipoPropriedade.objects.all(), slug_field='id')
endereco = serializers.SlugRelatedField(queryset=Endereco.objects.all(), slug_field='id')
proprietario = serializers.SlugRelatedField(queryset=Usuario.objects.all(), slug_field='id')
estacionamentos = serializers.SlugRelatedField(many=True, queryset=Estacionamento.objects.all(), slug_field='id')
recepcao = serializers.SlugRelatedField(queryset=TipoRecepcao.objects.all(), slug_field='id')
comodidades = serializers.SlugRelatedField(many=True, queryset=ComodidadePropriedade.objects.all(), slug_field='id')
class Meta:
model = Propriedade
fields = '__all__'
---------------------------------------------------------------------------------------------------------------
But I am still getting these errors:
---------------------------------------------------------------------------------------------------------------
{'tipo': [ErrorDetail(string='Invalid value.', code='invalid')], 'endereco': [ErrorDetail(string='Invalid value.', code='invalid')], 'proprietario': [ErrorDetail(string='Invalid value.', code='invalid')], 'estacionamentos': [ErrorDetail(string='This field is required.', code='required')], 'recepcao': [ErrorDetail(string='Invalid value.', code='invalid')], 'comodidades': [ErrorDetail(string='Invalid value.', code='invalid')], 'estrelas': [ErrorDetail(string='This field is required.', code='required')]}
---------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------
class PropriedadeSerializer(WritableNestedModelSerializer):
tipo = TipoPropriedadeSerializer()
endereco = EnderecoSerializer()
proprietario = UsuarioSerializer()
estacionamentos = EstacionamentoSerializer(many=True)
recepcao = TipoRecepcaoSerializer()
comodidades = ComodidadePropriedadeSerializer(many=True)
class Meta:
model = Propriedade
fields = '__all__'
---------------------------------------------------------------------------------------------------------------
But I got these errors:
---------------------------------------------------------------------------------------------------------------
{'tipo': {'tipo': [ErrorDetail(string='This field is required.', code='required')]}, 'endereco': {'logradouro': [ErrorDetail(string='This field is required.', code='required')], 'complemento': [ErrorDetail(string='This field is required.', code='required')], 'cep': [ErrorDetail(string='This field is required.', code='required')]}, 'proprietario': {'password': [ErrorDetail(string='This field is required.', code='required')], 'username': [ErrorDetail(string='This field is required.', code='required')], 'first_name': [ErrorDetail(string='This field is required.', code='required')], 'last_name': [ErrorDetail(string='This field is required.', code='required')], 'email': [ErrorDetail(string='This field is required.', code='required')], 'telefone_celular': [ErrorDetail(string='This field is required.', code='required')]}, 'estacionamentos': [{'tipo': [ErrorDetail(string='This field is required.', code='required')]}], 'recepcao': {'tipo': [ErrorDetail(string='This field is required.', code='required')]}, 'comodidades': [{'tipo': [ErrorDetail(string='This field is required.', code='required')]}, {'tipo': [ErrorDetail(string='This field is required.', code='required')]}, {'tipo': [ErrorDetail(string='This field is required.', code='required')]}]}
---------------------------------------------------------------------------------------------------------------
It seems like it's expecting all the embedded fields within the POST request but it's not the best approach to my project.
I also read the documentation about Wiritable Nested Serializers:
And I am confused. I will have to create all the relationships by myself? One by one? I am not sure how to deal with this to ManyToMany fields for example.
So I am very confused about how to perform POSTs with DRF. What is the best approach to perform this action? Am I right to deal with this using PrimaryKeyRelatedField?
I also tried the rest_framework_json_api but it has lots of fields equired by the JSON:API and it makes everything more complex.
I would appreciate your help and suggestion on how to solve this problem.
Thank you.