Error using a base class field in subclass unique_together meta option

This is by design. Reading the documentation for the unique_together option, it states that:

It's used in the Django admin and is enforced at the database level.

If you look at the table that a subclass creates, you'll see that it doesn't actually have the fields that its parent has. Instead, it gets a soft Foreign Key to the parent table with a field name called [field]_ptr_id, where [field] is the name of the table you're inheriting from excluding the app name. So your division table has a Primary Foreign Key called organization_ptr_id.

Now because unique_together is enforced at the database level using the UNIQUE constraint, there's no way that I know of for the database to actually apply that to a field not in the table.

Your best bet is probably through using Validators at your business-logic level, or re-thinking your database schema to support the constraint.

Edit: As Manoj pointed out, you could also try using Model Validators such as validate_unique.


This is a solution I recently used in Django 1.6 (thanks to Manoj Govindan for the idea):

class Organization(models.Model):
    name = models.CharField(max_length="100",)
    alias = models.SlugField()
    ...

class Division(Organization):
    parent_org = models.ForeignKey(Organization)

    # override Model.validate_unique
    def validate_unique(self, exclude=None):     
        # these next 5 lines are directly from the Model.validate_unique source code
        unique_checks, date_checks = self._get_unique_checks(exclude=exclude)
        errors = self._perform_unique_checks(unique_checks)
        date_errors = self._perform_date_checks(date_checks)
        for k, v in date_errors.items():
            errors.setdefault(k, []).extend(v)

        # here I get a list of all pairs of parent_org, alias from the database (returned 
        # as a list of tuples) & check for a match, in which case you add a non-field 
        # error to the error list
        pairs = Division.objects.exclude(pk=self.pk).values_list('parent_org', 'alias')
        if (self.parent_org, self.alias) in pairs:
                errors.setdefault(NON_FIELD_ERRORS, []).append('parent_org and alias must be unique')

        # finally you raise the ValidationError that includes all validation errors, 
        # including your new unique constraint
        if errors:
            raise ValidationError(errors)

[Model] Validators would work for you. Perhaps simplest, though, would be to use:

class BaseOrganization(models.Model):
    name = models.CharField(max_length="100",)
    alias = models.SlugField()
    class Meta:
        abstract = True

class Organization(BaseOrganization):
    pass

class Division(BaseOrganization):
    parent_org = models.ForeignKey(Organization)

    class Meta:
        unique_together=['parent_org', 'alias']

Note: as with your current code, you could not have subdivisions of divisions.