Применить уникальное ограничение к столбцам в двух отдельных таблицах (Django, postgres) - PullRequest
0 голосов
/ 16 октября 2018

Итак, я собираю сайт, который работает немного как github, где и пользователи, и организации имеют дескриптор:

class User(AbstractUser):
    """ Using django's default user model, with its username field which looks like:

        username = models.CharField(
            _('username'),
            max_length=150,
            unique=True,
            help_text=_('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.'),
            validators=[username_validator],
            error_messages={
                'unique': _("A user with that username already exists."),
            },
        )
    """

    # Many users to many organisations
    organisations = ManyToManyField('Organisation', related_name='users', blank=True)

class Organisation(models.Model):

    # ...other stuff, id etc
    handle = CharField(unique=True, max_length=36, null=False)

Я создам URL с конечными точками, такими как mydomain.com/username_or_handle/stuff. Это создает конфликт, поскольку пользователь может иметь тот же дескриптор, что и организация.

Текущее решение:

У меня есть сигнал, который припредварительно сохраняя либо пользователя, либо организацию, просматривает ОБА таблицы для обеспечения уникальности и выдает ValidationError в случае его нарушения.

@receiver(pre_save, sender=User)
@receiver(pre_save, sender=Organisation)
def check_valid_handle(sender, instance, **kwargs):
    """ The abbreviated gist...
    """
    if (Organisation.objects.filter(handle=instance.handle).count() > 0) or (User.objects.filter(username=instance.handle).count() > 0):
        raise ValidationError(detail='This handle is already taken, or prohibited. Please try another.'.format(type_str))

Но, строго говоря, это может привести к гонкеусловие, поскольку между временем проверки и временем создания / обновления модели не применяется блокировка.Кроме того, это кажется хакерским.

Возможно ли применить это ограничение на уровне БД, не меняя принципиально мои модели для многотабличного наследования или полиморфизма (что может стать кошмаром для работы с AbstractUser без особых затрат?)хирургии)?И если да, то как?

...