Django:允许选择许多OneToOneFields

时间:2015-11-24 13:08:45

标签: python django django-models

我正在创建一个系统,用户可以使用3种帐户类型之一(Musician,Blogger或Listener)。我已经完成了这个,但我不确定这是最好的方法。

当前解决方案

在当前系统中,我有一个自定义用户模型,其CharField account_type的三个account_types的选项属性为'M', 'L', or 'B'。 Blogger,Musician和Listener有三种模式。我在创建帐户后使用信号分配account_type。

用户模型:

class User(AbstractBaseUser, PermissionsMixin):
    """
    A copy of the django default user model with additional account_type and email used as username.

    Password, account_type and email are required. Other fields are optional.
    """
    ACCOUNT_TYPES = (
        ('M', 'Musician'),
        ('B', 'Blogger'),
        ('L', 'Listener')
    )
    first_name = models.CharField(max_length=30, blank=True)
    last_name = models.CharField(max_length=30, blank=True)
    email = models.EmailField(unique=True)
    account_type = models.CharField(max_length=1, choices=ACCOUNT_TYPES, default='L')
    ...

Receivers.py:

@receiver(post_save, sender=User, dispatch_uid='associate_account_type_post_save')
def post_save_receiver(sender, instance, created, **kwargs):
    if created:
        AccountType(instance).associate(instance.account_type)


@receiver(user_signed_up)
def user_signed_up_receiver(request, user, **kwargs):
    AccountType(user).associate(user.account_type)

AccountType(user).associate(account_type)是一个辅助函数,首先检查用户是否与其中一个帐户类型有关系,如果是,则删除它,然后创建新关系。我不认为这个问题的代码与问题有关,所以没有包括在内。

由于使用了allauth,因此需要两个接收器。由于我在User模型中添加了一列,因此我还使用account_type的选择字段创建了一个自定义表单。 Allauth在两次保存后触发user_signed_up信号;首先使用标准表单字段创建模型,然后保存自定义表单字段。我还必须使用post_save信号来确保通过Django的管理界面创建用户时我也设置的关系。

替代解决方案

最好不要有两个最终具有相同功能的接收器,而不是一个冗余的列。一个好的替代方案是在用户模型中有一个没有相应列但具有对应关系的字段。因此,没有'M', 'B', or 'L'字符串保存到数据库,但会自动创建关系。

通过这种方式,我们可以简单地通过User.musician查询该用户是否是音乐家并捕获DoesNotExist例外。

我能想到的唯一方法就是将请求包含在信号中。这样我可以使用相同的接收器,只需将user.account_type替换为request.cleaned_data['account_type']

我不确定这是否可以在Django中完成,并希望有人能够启发我。

0 个答案:

没有答案