简体   繁体   中英

How to implement multiple roles in Django?

I want to do a application with manages roles, and where one User can have multiple roles. I have created two models, one for the roles and other for the Users in models.py. My models.py looks like this:

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)

Now what I want to do is establish the roles from the User form. My forms.py looks like this:

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',)

And the views.py looks like this:

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')

How can I make to show all the roles in the User form and select multiple roles from there?

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM