Bastien
Bastien

Reputation: 1487

Django - Optional field with Serializer

I want to automatically generate the "path" field of my model when I use the create method of my serializer. Otherwise I would like to be able to pass this field in my request to be able to modify it later. I haven't found a way to make a single field of my template optional. Here is my model :

models.py

class Shop(models.Model):
    name = models.CharField(max_length=255)
    category = models.ForeignKey(ShopCategory, on_delete=models.SET_NULL, null=True, blank=True)
    description = models.TextField(blank=True, null=True)
    path = models.CharField(max_length=255, unique=True)
    mustBeLogged = models.BooleanField(default=False)
    deliveries = models.FloatField(default=7)

    def __str__(self):
        return self.name

Here is my code :

serializer.py

class ShopSerializer(serializers.ModelSerializer):
    class Meta:
        model = Shop
        exclude = ['path']

    def create(self, validated_data):
        path = validated_data["name"].replace(" ", "-").lower()
        path = unidecode.unidecode(path)
        unique = False
        while unique == False:
            if len(Shop.objects.filter(path=path)) == 0:
                unique = True
            else:
                # Generate a random string
                char = "abcdefghijklmnopqrstuvwxyz"
                path += "-{}".format("".join(random.sample(char, 5)))
        shop = Shop.objects.create(**validated_data, path=path)
        shop.save()
        return shop

views.py

def post(self, request):
        """For admin to create shop"""
        serializer = ShopSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors)

Upvotes: 0

Views: 2729

Answers (1)

Neeraj
Neeraj

Reputation: 997

You can set path to be accepted as Null and pop it in create method. In this way you won't have to add it in exclude.

class ShopSerializer(serializers.ModelSerializer):
    path = serializers.CharField(allow_blank=True, allow_null=True)
    
    class Meta:
        model = Shop
        fields = '__all__'

    def create(self, validated_data):
        validated_data.pop('path')
        path = validated_data["name"].replace(" ", "-").lower()
        path = unidecode.unidecode(path)
        unique = False
        while unique == False:
            if len(Shop.objects.filter(path=path)) == 0:
                unique = True
            else:
                # Generate a random string
                char = "abcdefghijklmnopqrstuvwxyz"
                path += "-{}".format("".join(random.sample(char, 5)))
        shop = Shop.objects.create(**validated_data, path=path)
        shop.save()
        return shop
    
    def update(self, instance, validated_data):
        #You will have path in validated_data
        #And you may have to check if the values are null
        return super(ShopSerializer, self).update(instance, validated_data)

Apart from this, in your code:

while unique == False:
                if len(Shop.objects.filter(path=path)) == 0:

This would be very costly operation. In every loop it would fire a query, I'm not sure about the logic behind it but you may want to change this.

Upvotes: 1

Related Questions