Django: Add is_staff permission to user inside view based on a condition

90 Views Asked by At

I'm working on a Django (4.0+) project,, where I'm using the default User model for login, and a custom form for signup, and I have a Boolean field named: blogger in signup form, if user check this, i have to set is_staff true, otherwise it goes as normal user.

Here's what I have:

Registration Form:

class UserRegistrationForm(UserCreationForm):
    first_name = forms.CharField(max_length=101)
    last_name = forms.CharField(max_length=101)
    email = forms.EmailField()
    blogger = forms.BooleanField()

    class Meta:
        model = User
        fields = ['username', 'first_name', 'last_name', 'email', 'password1', 'password2', 'blogger', 'is_staff']

views.py:

def register(request):
    if request.method == 'POST':
        form = UserRegistrationForm(request.POST)
        if form.is_valid():
            print(form['blogger'])
            if form['blogger']:
                form['is_staff'] = True
            form.save()

            messages.success(request, f'Your account has been created. You can log in now!')    
            return redirect('login')
        else:
            print(form.errors)
    else:
        form = UserRegistrationForm()

    context = {'form': form}
    return render(request, 'users/signup.html', context)

Its giving an error as:

TypeError: 'UserRegistrationForm' object does not support item assignment

How can i achieve that?

2

There are 2 best solutions below

2
lucutzu33 On

You need to first save the user object, without commiting it to the database.

Also it's best practice to use form.cleaned_data to check the submitted data

form = UserRegistrationForm(request.POST)
if form.is_valid():
    user = form.save(commit=False)
    if form.cleaned_data['blogger']:
        user.is_staff = True
    user.save()
0
willeM_ Van Onsem On

You can handle this in the .save(…) method [Django-doc] where you can first set the cleaned data of is_staff to True if blogger is set to True:

class UserRegistrationForm(UserCreationForm):
    first_name = forms.CharField(max_length=101)
    last_name = forms.CharField(max_length=101)
    email = forms.EmailField()
    blogger = forms.BooleanField()

    def save(self, *args, **kwargs):
        self.cleaned_data['is_staff'] |= self.cleaned_data['blogger']
        return super().save(*args, **kwargs)

    class Meta:
        model = User
        fields = [
            'username',
            'first_name',
            'last_name',
            'email',
            'password1',
            'password2',
            'blogger',
            'is_staff',
        ]

Then we can use the form like any other form:

def register(request):
    if request.method == 'POST':
        form = UserRegistrationForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            messages.success(
                request, f'Your account has been created. You can log in now!'
            )
            return redirect('login')
    else:
        form = UserRegistrationForm()

    context = {'form': form}
    return render(request, 'users/signup.html', context)

Since your view however follows a boilerplate format, it might be easier to work with a class-based view:

from django.contrib.messages.views import SuccessMessageMixin
from django.views.generic.edit import CreateView


class RegisterView(SuccessMessageMixin, CreateView):
    form_class = UserRegistrationForm
    success_url = reverse_lazy('login')
    template_name = 'users/signup.html'
    success_message = 'Your account has been created. You can log in now!'