0

Say I have the following models:

class ParentModel(models.Model):
    parent_field_1 = models.CharField(max_length=10)
    parent_field_2 = models.CharField(max_length=10)

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=['parent_field_1', 'parent_field_2', 'child_field_2'],
                name='unique_parent_example'
            )
        ] 

class ChildModel(ParentModel):
    child_field_1 = models.CharField(max_length=10)
    child_field_2 = models.CharField(max_length=10)

I want to utilise the ParentModel's UniqueConstraint but apply an additional field within the ChildModel's UniqueConstraint. I know this is not possible but to help visualise the idea, I'd ideally like to do something like this:

class ChildModel(ParentModel):
    [.. fields ..]

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=['parentmodel', 'child_field_2'],
                name='unique_child_example'
            )
        ] 

Almost like I'm building the unique constraint as inheritance also.

How could I do this?

Lewis
  • 2,718
  • 1
  • 11
  • 28

1 Answers1

0

Multi-table inheritance (as you are using) uses a one to one relationship. this means that every parent can have only one child and vice versa

this would implicitly bring into effect the unique-ness of children as they can only relate to one parent, so if the parent is unique, so will the child.

in order to prevent duplicated information in the child model just apply meta constraints as in the parent or do unique=True in the fields

If you want only some of the columns in the child to be unique to the parent - then as you said - this is not possible. To achieve something like that you would need to split the child into multiple models - the unique stuff would remain in the child that inherited from the parent while the other stuff would be in another model that had a foreign key relationship to the parent

here is what I would do based on what you shared:

class ParentModel(models.Model):
    parent_field_1 = models.CharField(max_length=10)
    parent_field_2 = models.CharField(max_length=10)

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=['parent_field_1', 'parent_field_2'],
                name='unique_parent'
            )
        ] 

class ChildModel(ParentModel):
    child_field_2 = models.CharField(max_length=10, unique=true)
    # this being unique means that only one parent can have a child like this 


class UnInheritedChild(models.Model):
    child_field_1 = models.CharField(max_length=10)
    parent = models.ForeignKey(ParentModel, on_delete=models.CASCADE)

dafrandle
  • 78
  • 1
  • 8
  • Yes so I actually need the `child_field_2` itself, to not be unique as this will vary. – Lewis May 13 '22 at 06:07
  • if you don't put `unique=true` on `child_field_2` all that means is you could have multiple records in your `ChildModel` table that have the same data in the `child_field_2` column. If your going for some quasi-unique-ness where only some columns are enforced but not others and its conditional: 1. I have no idea what you want unless you use less generic names for your models so I can see some of the business rules that are in play. & 2. If you can't or won't break models apart into multiple models - you will have to write your own validation code in like `clean()` or `save()` – dafrandle May 13 '22 at 21:54
  • No you're right on the Money. I don't think it's even possible in MySQL to which a trigger has to be used to form a unique contraints across multiple tables: https://stackoverflow.com/questions/408749/enforce-unique-values-across-two-tables. Therefore as you rightly said I have developed a pseudo unique constraint in the `clean()` to unsure this constraint is in place. Not Ideal, but it works. – Lewis May 15 '22 at 16:55