将唯一约束应用于两个单独表(Django,postgres)上的列

时间:2018-10-16 15:45:45

标签: django python-3.x postgresql unique-constraint

因此,我正在整理一个类似于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)

我将使用mydomain.com/username_or_handle/stuff之类的端点来设置URL。 这会造成冲突,因为用户可能具有与组织相同的句柄。

当前解决方案:

我有一个信号,在用户或组织的预先保存下,同时查找两个表以确保唯一性,如果违反了,则引发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))

但是严格来说,这可能会受到竞争条件的影响,因为在检查时间与模型创建/更新时间之间未应用锁定。此外,感觉很hacky。

是否有可能在数据库级别应用此约束,而无需从根本上改变我的模型来进行多表继承或多态(这可能是噩梦,而无需进行大量操作即可使用AbstractUser)?如果可以,怎么办?

1 个答案:

答案 0 :(得分:0)

多年后,我注意到这个问题有一些活动,所以想发布一个准答案。

所以严格的答案(如评论中所示)是“不”,在您的数据库架构中执行此操作并不简单。

我走的路线

就我而言,我使 Organisation 派生自 django auth 的 Group 模型。

我还创建了一个 UserGroup,它派生自 Group 并与 User 具有 1:1 的关系。

然后我简单地使用了 Group 的 name 字段作为句柄,在那里有一个唯一的约束。工作完成。

我想的另一件事

当我写原始问题时,这不可用,但 django 现在有更多的 powerful constraints system 可用于对模型的创建或更新应用此类约束。