如何在Django中实现多个角色?

时间:2019-05-18 23:19:08

标签: python django django-models django-forms

我想创建一个具有管理角色的应用程序,并且一个用户可以拥有多个角色。我在models.py中创建了两个模型,一个用于角色,另一个用于Users。我的models.py看起来像这样:

class Role(models.Model):
    DOCTOR = 1
    NURSE = 2
    DIRECTOR = 3
    ENGENEER = 4
    ROLE_CHOICES = {
        (DOCTOR, 'doctor'),
        (NURSE, 'nurse'),
        (DIRECTOR, 'director'),
        (ENGENEER, 'engeneer'),
    }

    id = models.PositiveIntegerField(choices = ROLE_CHOICES, primary_key = True)

    def __str__(self):
        return self.get_id_display()

class User(AbstractUser):
    roles = models.ManyToManyField(Role)

现在我要做的是从“用户”表单中建立角色。我的forms.py看起来像这样:

class UserCreationForm(UserCreationForm):
    fields = ('username', 'password1', 'password2')
    model = User

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['username'].label = 'Insert username'
        self.fields['password1'].label = 'Insert password'
        self.fields['password2'].label = 'Again'


class RoleCreationForm(forms.ModelForm):
    class Meta:
        model = Role
        fields = ('id',)

然后views.py看起来像这样:

class UserCreateView(CreateView):
    model = User
    form_class = forms.UserCreationForm
    template_name = 'user_form.html'
    redirect_field_name = 'index.html'
    success_url = reverse_lazy('accounts:index')

class RoleCreateView(CreateView):
    model = Role
    form_class = forms.RoleCreationForm
    template_name = 'role_form.html'
    redirect_field_name = 'index.html'
    success_url = reverse_lazy('accounts:index')

我该如何显示“用户”表单中的所有角色并从中选择多个角色?

1 个答案:

答案 0 :(得分:1)

I assume your UserCreationForm is subclass of forms.ModelForm as well:

1) There are no password1 or password2 field in User model - only password. Hence, to make password confirmation you have to specify confirm_password field and override clean method to check that they are equal.

2) To show roles in form, you can just specify 'roles' in list of fields. Since roles field exist in User model, django will find correct widget, display and validate it correctly.

3) You didn't wrote about it, but I guess you added AUTH_USER_MODEL = '<you_app_name>.User' to settings.py? That will change default User model to your app model.

4) Your UserCreateView will store password in plain text, which is very bad idea. Read more about password management on how to properly store passwords.

class UserCreationForm(forms.ModelForm):
    confirm_password = forms.CharField(widget=forms.PasswordInput())

    class Meta:
        fields = ('username', 'password', 'confirm_password', 'roles')
        model = User
        widgets = {
            'password': forms.PasswordInput(),
            'roles': forms.CheckboxSelectMultiple()
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['username'].label = 'Insert username'
        self.fields['password'].label = 'Insert password'

    def clean(self):
        cleaned_data = super().clean()

        password = cleaned_data.get("password")
        confirm_password = cleaned_data.get("confirm_password")

        if password != confirm_password:
            raise forms.ValidationError(
                "password and confirm_password does not match"
            )

In reality you probably want to just create additional model with OneToOneField to User and ManyToManyField to Role instead of overriding django User, since replacing django User model can lead to problems.

Check out django authentication views. You can subclass AuthenticationForm to add Roles.