Jeet Patel
Jeet Patel

Reputation: 1241

Unable to insert data into models using DRF due to TypeError Object of type IntegrityError is not JSON serializable

I have a form-data which I want to insert into two different models. So at first I created both the models as shown below -

This is the model User.

class User(AbstractBaseUser, PermissionsMixin):

    first_name = models.CharField(max_length=255, blank=False)
    last_name = models.CharField(max_length=255, blank=False)
    email = models.EmailField(max_length=255, blank=False, unique= True)
    phone_number = models.BigIntegerField(blank=False, unique= True)
    password = models.TextField(blank=False)
    company_name = models.CharField(max_length=255, blank=True)
    is_active = models.BooleanField(default= True)
    role = models.ForeignKey(Role, on_delete=models.CASCADE, blank=False)
    business = models.ForeignKey(Businesses, on_delete=models.CASCADE, blank=True)

    objects = UserManager()

    USERNAME_FIELD = 'email'

    def __str__(self):

        return 'User Object ({})'.format(self.id)

This is the model DeliveryAgent.

class DeliveryAgentVehicle(models.Model):
    vehicle_model = models.CharField(max_length=255, blank=False)
    year_of_make = models.IntegerField(blank=False)
    vehicle_photo = models.ImageField(upload_to='vehicle_photo/', max_length=None, null=True, blank=False)
    driver_license = models.ImageField(upload_to='driver_license/', max_length=None, blank=False)
    user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True)

    def __str__(self):

        return 'DeliveryAgentVehicle Object ({})'.format(self.id)

This is my form-data

Then I created APIView called DeliveryAPIView().

In this view at first I have declared parser_classes. Then in post method I updated request.data dictionary by adding key as a role and id (of role Delivery_agent) as value. I did this so that this view would only create user of type Delivery_Agent

class DeliveryAPIView(APIView):

    parser_classes = (FormParser, MultiPartParser)

    def post(self, request, format=None):

        request.data['role'] = Role.objects.get(role_name='Delivery_agent').id

        deserialized_data = DeliverySerializer(data=request.data)

        if deserialized_data.is_valid():
            try:
                delivery_agent = deserialized_data.save()
            except IntegrityError as identifier:
                return Response(identifier)
        return Response({
            "message":"Done"
        })

As I want to store the form-data into two different model, I have splited validate_data dictionary into two saperate dictionaries delivey_agent_vehicle and delivery_agent in serializer.

To map the vehicle details with the delivery agent I first need to have the user_id of delivery agent. So to create delivery agent I had to pass dictionary delivey_agent to create_user() method which belongs to User model's manager. Then expecting that it will create delivery agent and return a string representation instance of the delivery agent I called create() method of DeliveryAgentVehicle to insert the vehicle details of the delivery agent.

This is how my serializer look like -

class DeliverySerializer(serializers.Serializer):
    email = serializers.EmailField(max_length=255, required=True)
    password = serializers.CharField(max_length=255, required=True)
    first_name = serializers.CharField(max_length=255, required=True)
    last_name = serializers.CharField(max_length=255, required=True)
    phone_number = serializers.IntegerField(required=True)
    role = serializers.IntegerField(required=True)
    vehicle_model = serializers.CharField(max_length=255, required=True)
    year_of_make = serializers.CharField(max_length=255, required=True)
    photo_of_vehicle = serializers.ImageField(max_length=None, allow_empty_file=False)
    driver_license = serializers.ImageField(max_length=None, allow_empty_file=False)

    def create(self, validated_data):

        validated_data['role'] = Role.objects.get(pk=validated_data['role'])

        delivey_agent={}

        delivey_agent['email'] = validated_data['email']
        delivey_agent['password'] = validated_data['password']
        delivey_agent['first_name'] = validated_data['first_name']
        delivey_agent['last_name'] = validated_data['last_name']
        delivey_agent['phone_number'] = validated_data['phone_number']
        delivey_agent['role'] = validated_data['role']

        agent_id = User.objects.create_user(**delivey_agent)

        delivey_agent_vehicle={}

        delivey_agent_vehicle['vehicle_model'] = validated_data['vehicle_model']
        delivey_agent_vehicle['vehicle_model'] = validated_data['year_of_make']
        delivey_agent_vehicle['vehicle_model'] = validated_data[ 'photo_of_vehicle']
        delivey_agent_vehicle['vehicle_model'] = validated_data['driver_license']
        delivey_agent_vehicle['user'] = agent_id

        agent_vehicle_id = DeliveryAgentVehicle.objects.create(**delivey_agent_vehicle)

        print(delivey_agent_vehicle)
        print(delivey_agent)

        return agent_id

This is the error which it has returned -

Internal Server Error: /users/delivery/signup/
Traceback (most recent call last):
  File "/Users/jeetpatel/Desktop/env/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/Users/jeetpatel/Desktop/env/lib/python3.7/site-packages/django/core/handlers/base.py", line 145, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/Users/jeetpatel/Desktop/env/lib/python3.7/site-packages/django/core/handlers/base.py", line 143, in _get_response
    response = response.render()
  File "/Users/jeetpatel/Desktop/env/lib/python3.7/site-packages/django/template/response.py", line 105, in render
    self.content = self.rendered_content
  File "/Users/jeetpatel/Desktop/env/lib/python3.7/site-packages/rest_framework/response.py", line 70, in rendered_content
    ret = renderer.render(self.data, accepted_media_type, context)
  File "/Users/jeetpatel/Desktop/env/lib/python3.7/site-packages/rest_framework/renderers.py", line 103, in render
    allow_nan=not self.strict, separators=separators
  File "/Users/jeetpatel/Desktop/env/lib/python3.7/site-packages/rest_framework/utils/json.py", line 25, in dumps
    return json.dumps(*args, **kwargs)
  File "/usr/local/opt/python/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/__init__.py", line 238, in dumps
    **kw).encode(obj)
  File "/usr/local/opt/python/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/local/opt/python/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "/Users/jeetpatel/Desktop/env/lib/python3.7/site-packages/rest_framework/utils/encoders.py", line 67, in default
    return super().default(obj)
  File "/usr/local/opt/python/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type IntegrityError is not JSON serializable

Upvotes: 1

Views: 73

Answers (1)

Ken4scholars
Ken4scholars

Reputation: 6296

Your error is here:

        try:
            delivery_agent = deserialized_data.save()
        except IntegrityError as identifier:
            return Response(identifier)

Response expects a JSON serializable object to return to the user which is usually the serializer data, a dictionary. However, you're passing it the IntegrityError object that you catch.

If you want to return the raw DB error message to the client(which is not advisable), you should do something like this instead:

try:
    delivery_agent = deserialized_data.save()
except IntegrityError as identifier:
    return Response({
        "message":str(identifier)
    }, status=400)

Upvotes: 1

Related Questions