有没有办法将两个变量设置为唯一变量?

时间:2019-08-05 14:26:33

标签: python django python-2.7 python-2.x unique-constraint

我正在创建一个具有相同用户名和昵称的应用程序:

username = models.CharField(
    max_length=40, unique=True, db_index=True)
nickname = models.CharField(max_length=100, unique=True)

但是我需要将这两个变量定义为唯一的,例如:

如果用户A具有:

username: bird
nickname: dog

和用户B尝试进行注册,例如:

username: dog
nickname: butterfly

我不会接受,因为已经使用了dog。或者,如果用户尝试将昵称与用户名相同。

我正在考虑创建一个注册视图以手动进行此验证。但是在声明中有没有办法做到这一点?

2 个答案:

答案 0 :(得分:0)

您可以在Meta下使用unique_together设置。

例如

class Meta: 
    unique_together = [[field1, field2]]

在您的情况下,这意味着鸟/狗和鸟/蝴蝶将是独特的。由于字段与鸟/狗不同,因此允许使用dod / bird,但不允许第二只鸟/狗。

答案 1 :(得分:0)

SQL通常不是为了在两列之间强制执行唯一性而设计的,所以我知道的唯一解决方案是使用split this up into two tables, one for typed names, and one for all other user information。您可以通过以下方式使答案适应模型:

class User(models.Model):
    # Define fields aside from username and nickname here

class Name(models.Model):
    user = models.ForeignKey('Users', on_delete=models.CASCADE)
    USERNAME = 'U'
    NICKNAME = 'N'
    TYPE_CHOICES = (
        (USERNAME, 'username'),
        (NICKNAME, 'nickname')
    )
    type = models.CharField(max_length=1, choices=TYPE_CHOICES)
    name = models.CharField(max_length=100, unique=True)

    class Meta:
        constraints = [
            models.UniqueConstraint(fields=['user', 'type'], name='unique_user_type'),
        ]

        # Alternative more concise, but semi-deprecated, approach:
        # unique_together = [['user', 'type']]

这样做,所有名称都使用一个共享列。它有一个unique约束,因此,用户名或昵称都不能出现两次。同样,usertype字段上的组合唯一性约束意味着任何给定用户只能拥有名称,用户或昵称的每个type中的一个,而外键关系意味着您可以通过User模型访问用户名/昵称数据,并且on_delete=models.CASCADE设置意味着如果删除了关联的用户,则关联的名称也会被删除。

主要缺点是:

  1. 这不会强制您为给定用户创建usernamenickname;您的程序逻辑必须确保除非usernamenickname都有效,否则永远(永久)不会创建用户
  2. 第1项表示您必须显式地进行事务操作,而不是依赖于按表插入原子性;创建新用户时,您需要开始事务,创建用户,刷新以获取有效的用户ID,然后使用新用户ID创建两个名称,如果在进行过程中违反任何约束,则回滚整个事务
  3. 无法为用户名和昵称定义不同的限制;由于它们共享一个字段,因此您不能对每个字段施加不同的长度限制(您的包装程序代码可以这样做,但是数据库无法尝试根据不同的限制来节省空间,即使您使用了复杂的{{1} }施加独立限制)

话虽如此,我不鼓励这种方法。如果昵称与安全性不相关,则可以允许它们重叠(StackOverflow允许这样做;指向用户配置文件的链接是您区分其他人的方式);他们实际上根本不需要唯一。用户名显然需要唯一,但是如果昵称仅用于显示,则无需防止昵称与用户名重叠。