简体   繁体   中英

KeyError DRF when posting

I get KeyError when I post and I don't write either email or telephone. In my code, either email or telephone are required but not both of them. Why is this happening?

This is the serializer :

class OrderSerializer(serializers.ModelSerializer):
    class Meta:
        model = order
        fields = '__all__'
        extra_kwargs = {
            'email': {'required': False}, 'phonenumber': {'required': False}}

    def create(self, validated_data):
        order= Order.objects.create(
            email=validated_data['email'],
            phonenumber=validated_data['phonenumber'],
            food=validated_data['food']
        )
    

This is the model :

class Order(models.Model):
    date = models.DateTimeField(auto_now_add=True)
    email = models.EmailField(max_length=200, unique=True)
    phonenumber = models.IntegerField(unique=True)
    food= models.ManyToManyField('Food', related_name='orders', blank=True)
    
    def __str__(self):
        return self.food

This is the error :

django-challenge-back | Traceback (most recent call last):
django-challenge-back |   File "/usr/local/lib/python3.9/site-packages/django/core/handlers/exception.py", line 47, in inner
django-challenge-back |     response = get_response(request)
django-challenge-back |   File "/usr/local/lib/python3.9/site-packages/django/core/handlers/base.py", line 181, in _get_response
django-challenge-back |     response = wrapped_callback(request, *callback_args, **callback_kwargs)
django-challenge-back |   File "/usr/local/lib/python3.9/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
django-challenge-back |     return view_func(*args, **kwargs)
django-challenge-back |   File "/usr/local/lib/python3.9/site-packages/django/views/generic/base.py", line 70, in view
django-challenge-back |     return self.dispatch(request, *args, **kwargs)
django-challenge-back |   File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 509, in dispatch
django-challenge-back |     response = self.handle_exception(exc)
django-challenge-back |   File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 469, in handle_exception
django-challenge-back |     self.raise_uncaught_exception(exc)
django-challenge-back |   File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
django-challenge-back |     raise exc
django-challenge-back |   File "/usr/local/lib/python3.9/site-packages/rest_framework/views.py", line 506, in dispatch
django-challenge-back |     response = handler(request, *args, **kwargs)
django-challenge-back |   File "/usr/local/lib/python3.9/site-packages/rest_framework/generics.py", line 190, in post
django-challenge-back |     return self.create(request, *args, **kwargs)
django-challenge-back |   File "/usr/local/lib/python3.9/site-packages/rest_framework/mixins.py", line 19, in create
django-challenge-back |     self.perform_create(serializer)
django-challenge-back |   File "/usr/local/lib/python3.9/site-packages/rest_framework/mixins.py", line 24, in perform_create
django-challenge-back |     serializer.save()
django-challenge-back |   File "/usr/local/lib/python3.9/site-packages/rest_framework/serializers.py", line 205, in save
django-challenge-back |     self.instance = self.create(validated_data)
django-challenge-back |   File "/app/order/serializers.py", line 39, in create
django-challenge-back |     email=validated_data['email'],
django-challenge-back | KeyError: 'email'
django-challenge-back | [16/Apr/2021 20:02:22] "POST /pedido HTTP/1.1" 500 103807

Answer for original question:

email=validated_data['email'] will throw KeyError if email is not in validated_data , the same for phonenumber .

You can check if the key exists beforehand or use the .get syntax to avoid the error and get a None value if not present.

email=validated_data.get('email') will return None if the email is not present, instead of the KeyError .


Edit for new approach:

You need to allow null values if they will not be required (see the added null=True in email and phonenumber):

class Order(models.Model):
    date = models.DateTimeField(auto_now_add=True)
    email = models.EmailField(max_length=200, unique=True, null=True)
    phonenumber = models.IntegerField(unique=True, null=True)
    food= models.ManyToManyField('Food', related_name='orders', blank=True)

Now neither email or phonenumber are required. If you want to have one of them required add a validate method to your serializer to check that one of them is present.

Something like:

class OrderSerializer(serializers.ModelSerializer):

    def validate(self, data):
        email = data.get('email')
        phonenumber = data.get('phonenumber')

        if not email and not phonenumber:
            raise serializers.ValidationError("one of email or phone number required")

        return data

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM