0

I have a model called Company. In a second model which is Branch, I use Company as a foreign key.

class Branch(models.Model):
    company = models.ForeignKey(Company, on_delete=models.CASCADE)

Now in some other model, I want to set a property(name) unique together with the Company but I use the branch as a foreign key.

class ABC(models.Model):
    name = models.CharField()
    branch = models.ForeignKey(Branch, on_delete=models.CASCADE)

    class Meta:
        unique_together = (
            ('branch__company', 'name'),
        )

Can I do something like the above? It gives me an error that the field is nonexistent. Or can I use both company and branch in my model as foreign key?

class ABC(models.Model):
    name = models.CharField()
    branch = models.ForeignKey(Branch, on_delete=models.CASCADE)
    company = models.ForeignKey(Company, on_delete=models.CASCADE)

    class Meta:
        unique_together = (
            ('company', 'name'),
        )

I want to attach ABC object with a branch but if once added it should be unique to that company (other branches of that company can not have the same name).

Read about the circular error and was thinking of the same here. Unique together will be depreciated in the future but I'm not thinking about this right now.

Any advice?

Alain Bianchini
  • 3,883
  • 1
  • 7
  • 27
Ranu Vijay
  • 1,137
  • 9
  • 18
  • Did you try what you suggest? In this case, what is (are) the error message(s)? – Christophe Apr 07 '22 at 13:59
  • I was worried about getting circular error, so have not tried using both company and branch as foerign key. Nor have I any experience with circular errors. In first case I get branch__Company is nonexistent. Ok wait let me try with both. – Ranu Vijay Apr 07 '22 at 14:06
  • Hi, I think the error that the field is not existent comes from the fact that your reference is wrong. It should be something like unique_together = ('branch__tenant', 'name') or ('branch__tenant__id', 'name') – Boketto Apr 07 '22 at 14:22
  • Does your branch model have a field name Company? – Mojtaba Apr 07 '22 at 14:25
  • 1
    @Boketto that tenant is actually company and it is there. sorry, i wrote it wrong there. – Ranu Vijay Apr 07 '22 at 14:29
  • @Mojtaba yes it has. – Ranu Vijay Apr 07 '22 at 14:29
  • Ok, seems that this is not possible with unique_together in general: https://stackoverflow.com/questions/4440010/django-unique-together-with-foreign-keys – Boketto Apr 07 '22 at 14:31
  • @Boketto thanks for the link, and so i'm still dealing with 11 year old problem :( :( – Ranu Vijay Apr 07 '22 at 14:37

1 Answers1

1

I suggest you to perform validation in the clean method (without a database constraint):

from django.core.exceptions import ValidationError


class ABC(models.Model):
    name = models.CharField()
    branch = models.ForeignKey(Branch, on_delete=models.CASCADE)
    
    def clean(self):
       super().clean()
       
       if ABC.objects.filter(name=self.name, branch__company=self.branch.company).exists():
          raise ValidationError('Error message')
 
    def save(self, *args, **kwargs):
       # Forces the clean method to be called
       self.full_clean()
       super().save(*args, **kwargs)
Alain Bianchini
  • 3,883
  • 1
  • 7
  • 27
  • @RanuVijay, you need to iterates through the queryset, for each item you update fields and then call save. For example: `for element in model.objects.all(): element.foo = 'new_value' element.save()` – Alain Bianchini Apr 07 '22 at 16:49
  • will this also work during the update ?? if someone tries to put the same name during the update process ?? – Ranu Vijay Apr 07 '22 at 16:50
  • You don't need to call `update`. You simply update the fields and then call save. As I did in my previous comment. – Alain Bianchini Apr 07 '22 at 16:50
  • 1
    will try this and let you know. – Ranu Vijay Apr 07 '22 at 17:13
  • I finally wrote object-level validation on my serializers def validate(self, data): and so on. I understood it was never going to be at the database level( in general terms) – Ranu Vijay Apr 07 '22 at 19:11