2

I am trying to implement my own validation for a many-to-many relation (m2m) since django does not allow m2m fields in the unique-together constraint (https://code.djangoproject.com/ticket/702) (Django Unique Together (with foreign keys))

What I want is to check is if a newly created object instance is already existent within the scope of a m2m related model.

Imagine I have the following 3 models:

class Juice(model.Model)
   name=CharField,
   year=IntegerField,
   flavor=CharField
class Company(model.Model)
    name=CharField,
    cooperates=ManytoManyField
    juice=ManytoManyFiedl
class Cooperate(model.Model)
    name=CharField

That means that a company can have many juices and many juices can belong to many companies. Equally a company can belong to many cooperates and a cooperate can belong to many companies.

What I want to implement now is the following restriction: Whenever I create a new juice with name, year and flavor it should validate if a juice like this already exists within the scope of the Cooperate model. That means if there is any company within the cooperates that already have this juice it should raise a ValidationError. Let's say for example I create a new juice (bb-sparkle, 2020, blueberry) it should raise a validation if cooperate-optimusprime already has a company (e.g. company-truck-juices) that has a juice with bb-sparkle, 2020, blueberry. But it should not raise an error when I create the same juice (bb-sparkle, 2020, blueberry) for the cooperate coorperate-megatron that has a company (e.g. company-airplane-juices).

What I am trying to do is to overwrite the validation method before saving an object:

    def validate_unique(self, exclude=None):
        """Overwrite validation to check for uniqueness within cooperate scope."""

        juice = Juice.objects.filter(
            year=self.year,
            name=self.name,
            flavor=self.flavor,
        )
        for j in juice:
            for company in j.company_set.all():
                for cooperate in company.cooperates.all():
                    if cooperate is not None:
                        print(cooperate)
                        raise ValidationError(
                            'Juice instances must be unique within cooperate scope.'
                        )

    def save(self, *args, **kwargs):
        """Overwrite save to call validation before saving."""

        self.validate_unique()
        super(Juice, self).save(*args, **kwargs)

This does not work since I am only checking if the cooperate is not None. But I don't really know how I can filter this correctly because I only have access to the parameters in the self-object.

Any help is much appreciated. Thanks in advance!

shadow
  • 151
  • 2
  • 12
  • 1
    How does the juice know for which cooperate it is being created for? – Brian Destura Jun 29 '21 at 00:48
  • Ah good question I should have added that. I am overwriting the create method on the serializer when I am using an API call. If created in the django backend, via selection of the company (which is connected to a cooperate) – shadow Jun 29 '21 at 12:33
  • You can add something like this in your serializer's `validate`: `Juice.objects.filter(year=year, name=name, flavor=flavor, company__cooperate__in=company.cooperate_set.all()).exists()`. You just need to pass the company in the context to be able to use it in the serializer – Brian Destura Jun 30 '21 at 01:39

0 Answers0