How to remove extra data from JSONField in django rest framework?

1.4k views Asked by At

I have a model like this:

class Things(models.Model):
    data = models.JSONField(default=dict)

and structure of data is like this:

{
   "item" : "sugar",
   "quantity" : "2",
   "cost" : 220
}

Note that it is not mandatory for data to contain all 3 keys, all of them are optional.

The difficult part is that I don't want any other keys, apart from these 3 keys, to be present in data field.

Creating a serializer can help to ensure presence and format of these 3 fields but it will not ensure absence of other fields. How can I achieve this thing in django rest framework?

2

There are 2 answers

3
Navid Zarepak On

You can validate the field in your serializer:

class ThingsSerializer(serializers.ModelSerializer):
    class Meta:
        model = Things
        fields = ['data']

    def validate_data(self, value):
        # You can validate, clean and change your data
        final_data = {
            "item": value.get("item"),
            "quantity": value.get("quantity"),
            "cost": value.get("cost", 0)
        }
        return final_data

You can also create a separate serializer for your data field and pass the value to it, validate each field there and return the final data. But this should do if your fields are limited and simple.

0
binpy On

By using validate_<field_name> in serializer level, you can also create an logic to makesure that all fields inside the data is required to fill.

class ThingsSerializer(serializers.ModelSerializer):
     data = serializers.JSONField()
 
     class Meta:
         model = Things
         fields = ('data', )
 
     def validate_data(self, data):
         valid_keys = ('item', 'quantity', 'cost')
         errors = []
         out_data = {}
 
         for key in valid_keys:
             if key in data.keys():
                 if data.get(key):
                     out_data[key] = data.get(key)
                 else:
                     errors.append({key: 'This field should be filled.'})
             else:
                 errors.append({key: 'This field is required'})
 
         if len(errors) > 0:
             raise serializers.ValidationError(errors)
         return out_data

Here is the tests:

In [25]: s = ThingsSerializer(data={'data': {'item': 'sugar', 'quantity': 2, 'cost': 20}})

In [26]: s.is_valid()
Out[26]: True

In [27]: s.errors
Out[27]: {}



In [28]: s = ThingsSerializer(data={'data': {'item': 'sugar', 'quantity': 2}})

In [29]: s.is_valid()
Out[29]: False

In [30]: s.errors
Out[30]: {'data': [{'cost': ErrorDetail(string='This field is required', code='invalid')}]}



In [34]: s = ThingsSerializer(data={'data': {'item': 'sugar', 'quantity': 2, 'cost': None}})

In [35]: s.is_valid()
Out[35]: False

In [36]: s.errors
Out[36]: {'data': [{'cost': ErrorDetail(string='This field should be filled.', code='invalid')}]}