DRF serializer validation - discard failed items, keep successful ones?

I have an endpoint (POST, APIView) which expects larger chunks of data that needs to be validated using serializers. However, for many reasons there are times where I'd like to discard a few of them that fail validation. The rest, I still want to add.

E.g I'd like to run :

serializer = ListingSerializer(data=request.data, many=True)
if serializer.is_valid():
   serializer.save()

Lets say we have a table of listings which has a foreign key to a company table. Therefore I have a nested company serializer as a field. A company only has a name. In order to save some performance I fetch all companies in the init method so is_valid() only makes one query (similar to a select_related).

The problem here is that if a single company did not exist, the entire is_valid() will fail and thus I cant run serializer.save(). Is there any elegant way to solve this by discarding the individual items that fail is_valid() so that I can run serializer.save()?

class CompanyStringSerializer(serializers.ModelSerializer):
    class Meta:
        model = Company
        fields = ("name",)


class ListingSerializer():
    company = CompanyStringSerializer()

    def __init__(self, *args, **kwargs):
        """
        This is executed when the serializer initializes (meaning the query will only run once)
        """
        self.companies = Company.objects.filter(enabled=True)
        super().__init__(*args, **kwargs)

    def validate_company(self, value):
        """
        This will run on each item & check if the items company name exists in the list of companies
        """
        try:
            company = next(
                item for item in self.companies if item.name == value["name"]
            )
        except StopIteration:
            print(f"company did not exist: {value['name']}")
            raise ValidationError("No such company exists")
        return company

    class Meta:
        model = Listing
        list_serializer_class = ListingListSerializer
        fields = "__all__"
Back to Top