pythondjangodjango-rest-frameworkmarshmallow

How can I make a "post" method in Python using the marshmallow?


I am working on a small project and have started using the marshmallow library for serialization. I want to write a post request to create a new object in the database, but during my development, I came across the fact that when executing the request, my object is not added to the database. Moreover, I have another error: response should return the id of new object.

serializer.py

class ObjectSerializer(Schema):
    operatorId = fields.String(required=True)
    operator = fields.String(required=True)
    inaction = fields.String(required=False)
    id = fields.Integer(required=False)

    def create(self, data: dict) -> dict:
        try:
            data = super().dump(data)
        except ValidationError as err:
            data = {'errors': err.messages}
        return data

controller.py

def post(self, params: dict) -> Tuple[dict, int]:
        logger.info('Adding new object for params: %s', str(params))
        data = ObjectSerializer().create(params)
        if 'errors' in data:
           logger.error('Error deserializing params: %s', str(data['errors']))
           return data, HTTPStatus.BAD_REQUEST.value
        return (
           data,
           HTTPStatus.OK.value
        )

views.py

def post(self, request: Request, *args, **kwargs) -> Response:
        query_data = request.data
        payload, status = self.controller.post(query_data)
        return Response(data=payload, status=status)

usecase.py

def create(self, operatorId: str, operator: str) -> ObjectEntity:
        return self.lead_repo.create(operatorId, operator)

entities.py

@dataclass()
class ObjectEntity:
    id: int
    operatorId: str = None
    createdAt: date = None
    operator: str = None
    inaction: int = 1

    @staticmethod
    def to_string(operatory: 'ObjectEntity') -> str:
        operatorId = f" ({operatory.operatorId}):" if operatory.operatorId else ValueError
        return f'{operatory.operatorId}{operatorId} {operatory.operator}'

Solution

  • First of all, you are using Django and DRF (based on your tags), so why not use the framework serializers instead of marshmallow (which would be more suited for Flask).

    But, to answer your question, you need a Model:

    class ObjectEntity(models.Model):
        operatorId = models.CharField(max_length=100)
        createdAt = models.DateField(auto_now_add=True)
        operator = models.CharField(max_length=100)
        inaction = models.IntegerField(default=1)
    

    A Schema (which is now the serializer):

    class ObjectSchema(Schema):
        id = fields.Integer(dump_only=True)
        operatorId = fields.Str()
        createdAt = fields.Date(dump_only=True)
        operator = fields.Str()
        inaction = fields.Integer()
    
        def create(self, data):
            try:
                errors = super().validate(data)
                if not errors:
                    obj = ObjectEntity.objects.create(**data)
                    return super().dump(obj)
                else:
                    raise ValidationError(errors)
                
            except ValidationError:
                return errors
    

    And, a view:

    class ListEntityAPIView(generics.ListCreateAPIView):
        queryset = ObjectEntity.objects.all()
        serializer_class = ObjectSchema
    
        def get(self, request, *args, **kwargs):
            objects = list(self.get_queryset())
            result = self.get_serializer(many=True).dump(objects)
            return JsonResponse(result, safe=False)
    
        def post(self, request, *args, **kwargs):
            result = self.get_serializer().create(request.data)
            return JsonResponse(result)
    

    Keep in mind that using the framework features as you should would make this code even cleaner.