Home > Mobile >  Condition whether field A or B is required in Django Rest Framework
Condition whether field A or B is required in Django Rest Framework

Time:11-20

I have a serializer in which I would like to give the opportunity to send a NEW address with a POST request OR give an ID of an already existing address. One of both is required, but right now it asks for both to be given.

Any possibility to achieve that it validates with a condition?

class OrderSerializer(serializers.ModelSerializer):

class Meta:
    model = Order
    #fields = '__all__'
    exclude = ['in_calculation','canceled',]
address = AdressSerializer()
addressid = serializers.CharField(source='address')
read_only_fields = ['id','user','status','costs','']

CodePudding user response:

You could use validate() and a customized create/update method like this:

class OrderSerializer(serializers.ModelSerializer):
    address_detail = AddressSerializer(write_only=True, required=False)

    class Meta:
        model = Order
        fields = (
            'address',         # to set from an existing address
            'address_detail',  # to create a whole new address
        )
        extra_kwargs = {
            'address': {'required': False},  # make `address` to optional if your address in model is required.
        }


    def validate(self, attrs):
        # if `address` and `address_detail` are both present or none of them is present
        if bool('address' in attrs) == bool('address_detail' in attrs):
            raise serializers.ValidationError('You can specify exactly one from these two fields.')

        return attrs

    def create(self, validated_data):
        # do custom logic

CodePudding user response:

class OrderSerializer(serializers.ModelSerializer):
    class Meta:
        model = Order
    
        extra_kwargs = {
            'address': {'required': False}, 
        }

        exclude = [] # some fields that should not be shown
        read_only_fields = [] # some fields that should not be edited

    # Add a nested Serializer to add new addresses while creating an order
    address_detail = addressSerializer(required=False)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        try:
            if "GET" in self.context['request'].method:
                self.fields['client'] = ClientSerializer()
                # ... some Nested Serializers which are ready-only on GET request.
        except KeyError:
            pass
    
    def create(self,validated_data):
        # check for uniqueness of ordernr and clientnr
        try:
            order = Order.objects.get(client=validated_data.get('client'),ordernr=validated_data.get('ordernr'))
            if order:
                raise ValidationError({'ordernr':'Ordernumber and Client-combination already exists'})
        except ObjectDoesNotExist:

            if validated_data.get('address_detail'):
                address_detail = validated_data.pop('address_detail')
                if address_detail: 
                    address, existent = address.objects.get_or_create(**address_detail)
                    order = Order.objects.create(**validated_data, address=address)
            elif validated_data.get('address'):
                order = Order.objects.create(**validated_data)
        return order

    def validate(self, data):
        validationerrors = {}
        print(data)
        # if `address` and `address_detail` are both present or none of them is present
        if bool('address' in data) == bool('address_detail' in data):
        validationerrors['address'] = "You need to specify exactly one from these two fields."   
        # a lot of other validations...
        if validationerrors:
            raise serializers.ValidationError(validationerrors)
        return data
  • Related