Hi there, Long-time lurker / Django user; first-time poster.
Ask: Any other ideas for ensuring that ForeignKey relationships are valid? Context / background: I'm working on a multitenant app, and looking at ways of ensuring the integrity of the data in the system. Specifically, I want to ensure that for a "tenant'ed" model that contains ForeignKey fields, those FK relations match the same tenant. Unfortunately CHECK constraints aren't suitable, as these are limited to just the row being inserted/updated, so nested SELECTs or similar at the database level aren't possible. It seems as if a TRIGGER could do the job, but I'm wary of going down this path if there are other solutions that I've missed. At present I've implemented something along the following simplified lines within the application. All ideas greatly appreciated. Thanks in advance :) # models.py class BaseModel(models.Model): match_fields: List[List[str]] = [] class Meta: abstract = True def clean(self): self.validate_matching_fields() return super().clean() def validate_matching_fields(self) -> None: for field_names in self.match_fields: field_values: Dict[str, Any] = dict() for field_name in field_names: value = self for field in field_name.split("."): value = getattr(value, field) field_values[field_name] = value _values = list(field_values.values()) assert len(_values) > 1 values_equal = all([V == _values[0] for V in _values]) if not values_equal: # pragma: no branch msg = f"One or more required fields not matching: {field_values}." raise ValidationError(msg) return # Tenant model class Organization(models.Model): name = models.CharField(max_length=64) class Author(models.Model): organization = models.ForeignKey(to=Organization, on_delete=models.CASCADE) name = models.CharField(max_length=64) # Target model # I want to ensure that BlogPost.organization == BlogPost.lead_author.organization class BlogPost(BaseModel): match_fields = [["organization.id", "lead_author.organization.id"]] organization = models.ForeignKey(to=Organization, on_delete=models.CASCADE) lead_author = models.ForeignKey(to=Author, on_delete=models.CASCADE) slug = models.SlugField(max_length=64) -- You received this message because you are subscribed to the Google Groups "Django users" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/18fe8095-3f46-44e6-b418-49e6a411667cn%40googlegroups.com.