How to assign users in groups from Django views? - django

I have CRUD operations for users, which can be done only from the admin role. I have 6 different roles, that I made by creating groups and assign users to specific group from the admin panel.
My question is is there some way to include these group fields with drop down menu when admin create new user, so he can choose what group to assign the new user but not from the admin panel?
any help would be appreciated :)
model.py
class CustomUserManager(BaseUserManager):
def create_user(self, email, password, **extra_fields):
if not email:
raise ValueError(_('The Email must be set'))
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save()
return user
def create_superuser(self, email, password, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_active', True)
if extra_fields.get('is_staff') is not True:
raise ValueError(_('Superuser must have is_staff=True.'))
if extra_fields.get('is_superuser') is not True:
raise ValueError(_('Superuser must have is_superuser=True.'))
return self.create_user(email, password, **extra_fields)
class CustomUser(AbstractUser):
username = None
email = models.EmailField(_('email address'), unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = CustomUserManager()
def __str__(self):
return self.email
username = models.CharField(max_length=30, blank=True, default='')
is_superuser = models.BooleanField(default=True)
is_admin = models.BooleanField(default=True)
is_employee = models.BooleanField(default=True)
is_headofdepartment = models.BooleanField(default=True)
is_reception = models.BooleanField(default=True)
is_patient = models.BooleanField(default=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=True)
forms.py
class UserForm(ModelForm):
class Meta:
model = CustomUser
fields = ['email', 'password',]
useradd.html
<h1 class="display-4">Add new user</h1>
<form action="" method="post" autocomplete="off">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-success">Save </button>
views.py
#login_required
#admin_only
def users(request):
context = {'users': CustomUser.objects.all()}
return render(request, 'users.html', context)
#login_required
def users_add(request):
if request.method == "POST":
form = UserForm(request.POST)
if form.is_valid():
users = CustomUser.objects.create_user(**form.cleaned_data)
#login(request, users)
# redirect, or however you want to get to the main view
return redirect('feedback:users')
else:
form = UserForm()
return render(request, 'useradd.html', {'form': form})

You can use ModelChoiceField to include select widget in your form. So please try this code:
forms.py
from django.contrib.auth.models import Group
from django.forms import ModelForm, ModelChoiceField
from app.model import CustomUser
class UserForm(ModelForm):
class Meta:
model = CustomUser
fields = [
'email',
'password',
]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['group'] = ModelChoiceField(
queryset=Group.objects.all(),
empty_label='No group'
)
Change CustomUserManager.create_user method in model.py
from django.contrib.auth.models import Group
class CustomUserManager(BaseUserManager):
def create_user(self, email: str, password: str, group: Group, **extra_fields):
if not email:
raise ValueError(_('The Email must be set'))
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save()
if group is not None:
group.user_set.add(user)
return user

Related

CustomUser created through Django Admin cannot login (Django Rest Framework)

I created a register/login system through DRF by overriding dj_rest_auth
If registering an user with Postman, by firing on the endpoint, that user can be used for login through endpoint
However, if creating an user through Django Admin, that user cannot be used for login through endpoint, and notably, if seen through Django Admin, the password is not hashed
How to handle this?
serializers.py
class CustomLoginSerializer(LoginSerializer):
def validate_auth_user_status(self, user):
request = self.context.get('request')
if not request.data.get('role'):
msg = 'Role is missing from the payload.'
raise exceptions.ValidationError(msg)
if not user.groups.filter(name=request.data.get('role')).exists():
msg = 'Invalid role for the user.'
raise exceptions.ValidationError(msg)
def create(self, validated_data):
pass # Empty because the function is not needed
# but Pylint demanded to implement it anyway
def update(self, instance, validated_data):
pass # Empty because the function is not needed
# but Pylint demanded to implement it anyway
class CustomRegisterSerializer(RegisterSerializer):
name = serializers.CharField()
def get_cleaned_data(self):
super().get_cleaned_data()
return {
'email': self.validated_data.get('email', ''),
'password1': self.validated_data.get('password1', ''),
'name': self.validated_data.get('name', '')
}
def create(self, validated_data):
pass # Empty because the function is not needed
# but Pylint demanded to implement it anyway
def update(self, instance, validated_data):
pass # Empty because the function is not needed
# but Pylint demanded to implement it anyway
def save(self, request):
user = super().save(request)
user.name = self.get_cleaned_data().get('name')
user.save()
client_role, _created = Group.objects.get_or_create(name='client')
user.groups.add(client_role)
return user
urls.py
urlpatterns = [
path('auth/registration/', include('dj_rest_auth.registration.urls')),
path('auth/', include('dj_rest_auth.urls')),
path('auth/user-login/', CustomLoginView.as_view(), name='custom_user_login'),
path('auth/google/', GoogleView.as_view(), name='google'),
]
models.py
class CustomUser(AbstractBaseUser, PermissionsMixin):
name = models.CharField(max_length=100)
email = models.EmailField(_('email address'), unique=True)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
date_joined = models.DateTimeField(default=timezone.now)
diet_profile = models.OneToOneField(
DietProfile,
on_delete=models.CASCADE,
primary_key=False,
related_name="user",
blank=True, null=True
)
nutritionist = models.ForeignKey(
Nutritionist,
on_delete=models.CASCADE,
related_name="clients",
blank=True,
null=True
)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = CustomUserManager()
def __str__(self):
return str(self.email)
EDIT:
adding custom user manager and admin.py
manager.py
class CustomUserManager(BaseUserManager):
"""
Custom user model manager where email is the unique identifiers
for authentication instead of usernames.
"""
def create_user(self, email, password, **extra_fields):
"""
Create and save a User with the given email and password.
"""
if not email:
raise ValueError(_('The Email must be set'))
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save()
client_role, _created = Group.objects.get_or_create(name='client')
user.groups.add(client_role)
return user
def create_superuser(self, email, password, **extra_fields):
"""
Create and save a SuperUser with the given email and password.
"""
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_active', True)
if extra_fields.get('is_staff') is not True:
raise ValueError(_('Superuser must have is_staff=True.'))
if extra_fields.get('is_superuser') is not True:
raise ValueError(_('Superuser must have is_superuser=True.'))
return self.create_user(email, password, **extra_fields)
admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import CustomUser
admin.site.register(CustomUser)

Creating new user with random password in django

I have been working on a project where admin registers users to use the website. say in my case admin registers teachers and students of the school. I need some way to create random password for every new user and a email will be sent using registered email with the password. I am using custom user model.
class MyAccountManager(BaseUserManager):
def create_user(self, email, username, password=None):
if not email:
raise ValueError("Users must have email Id")
if not username:
raise ValueError("Users must have an username")
user = self.model(email=self.normalize_email(email),
username=username)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, username, password=None):
user = self.create_user(email=self.normalize_email(email),
username=username,
password=password)
user.role = 'ADM'
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
class User(AbstractUser):
email = models.EmailField(verbose_name="Email", unique=True)
ROLE_CHOICES = [
('STD', 'STUDENT'),
('THR', 'TEACHER'),
('ADM', 'ADMIN')
]
role = models.CharField(max_length=3, choices=ROLE_CHOICES, default='STD')
username = models.CharField(max_length=50, unique=True)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
date_of_birth = models.DateField(null=True)
description = models.TextField(null=True)
image = models.ImageField(default='default.jpg', upload_to='profile_pics')
date_joined = models.DateTimeField(verbose_name="date joined", auto_now_add=True)
last_login = models.DateTimeField(verbose_name="last login", auto_now=True)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email']
objects = MyAccountManager()
here my register view.
#login_required
def register(request):
if not request.user.is_superuser:
return HttpResponse('Unauthorized', status=401)
if request.method == 'POST':
form = UserRegisterForm(request.POST)
if form.is_valid():
username = form.cleaned_data.get('username')
email = form.cleaned_data.get('email')
password = User.objects.make_random_password(length=10,
allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789')
form.save()
user = User.objects.filter(username=username)
user.set_password(password)
user.save()
send_mail(
'Login details',
'Here is your login details \n username : ' + username + '\n password : ' + password,
from_email=None,
recipient_list=[email],
fail_silently=False,
)
messages.success(message="Email has been sent to " + email + ".")
return redirect('register')
else:
form = UserRegisterForm()
return render(request, 'users/register.html', {'form': form})
here is my UserRegisterForm
class UserRegisterForm(UserCreationForm):
email = forms.EmailField(required=True)
def __init__(self, *args, **kwargs):
super(UserCreationForm, self).__init__(*args, **kwargs)
del self.fields['password1']
del self.fields['password2']
class Meta:
model = User
fields = ['username', 'email', 'role']
What are the possible ways I can set this. I tried by overriding form.save() by didnt seem to work.
Form .save() accepts an optional commit keyword argument, if you call save() with commit=False, then it will return an object that hasn’t yet been saved to the database. You can modify the data and then save it.
def register(request):
...
f = UserRegisterForm(request.POST)
if f.is_valid():
u = f.save(commit=False)
raw_password = User.objects.make_random_password(...)
u.set_password(raw_password)
u.save()
...
Template
<form action="..." method="post">
{% csrf_token %}
{{ form }}
<input type="password" name="password1" value="random_value" hidden>
<input type="password" name="password2" value="random_value" hidden>
<input type="submit" value="Submit">
</form>

My Django form is not validating and storing information in database

I have created a custom user model and using that model I have created sign up form. but whenever I click submit button ,form does not validate and don't store data in database. It just redirects me to home without storing data in database. but I can store data manually in database.
models.py
from django.db import models
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
class SignUpManager(BaseUserManager):
def create_user(self, email,age,name, username, password=None):
if not email:
raise ValueError("insert user")
if not username:
raise ValueError("insert username")
if not name:
raise ValueError("insert name")
if not age:
raise ValueError("insert age")
user = self.model(
email=self.normalize_email(email),
username=username,
age=age,
name=name,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email,name,age,username, password):
user = self.create_user(
email=self.normalize_email(email),
username=username,
password=password,
age=age,
name=name,
)
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
class UserSignupModel(AbstractBaseUser):
email = models.EmailField(verbose_name="email", max_length=60, unique=True)
age = models.CharField(max_length=15)
name = models.CharField(max_length=15)
username = models.CharField(max_length=15, unique=True)
date_joined = models.DateTimeField(verbose_name="date joined", auto_now_add=True)
last_login = models.DateTimeField(verbose_name="last login", auto_now=True)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
USERNAME_FIELD = "username"
REQUIRED_FIELDS = ['email','name','age']
objects = SignUpManager()
def __str__(self):
return self.email
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, app_label):
return True
#migrate --run-syncdb in case no work
forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from diabetes.models import UserSignupModel
class UserSignupForm(UserCreationForm):
email=forms.EmailField(max_length=60,help_text="add a valid email address")
name=forms.CharField(max_length=15,help_text="add a valid name")
age=forms.CharField(max_length=15)
class Meta:
model=UserSignupModel
fields=('email','name',"username",'age',"password1","password2")
views.py
from django.shortcuts import render,redirect
from django.contrib.auth import login,authenticate
from diabetes.forms import UserSignupForm
# Create your views here.
def home(request):
return render(request,'diabetes/home.html')
def signupuser(request):
if request.method == 'POST':
form=UserSignupForm(request.POST)
if form.is_valid():
form.save()
email=form.cleaned_data.get('email')
raw_password=form.cleaned_data.get('password1')
account=authenticate(email=email,password=raw_password)
login(request,account)
return redirect('home')
else:
return redirect('home')
else:
form = UserSignupForm()
return render (request,'diabetes/signupuser.html',{'form':form})
signupuser.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="POST">
{% csrf_token %}
{{ form.as_p}}
<input type="submit">SUBMIT</input>
</form>
</body>
</html>
You have got error in the signup method in views.py. Refer to this code and see what changes can be made.
# method for registration page
def register_view(request):
register_form = AddUserForm(request.POST or None)
# if the data provided in the form is valid than save the form
if register_form.is_valid():
user = register_form.save(commit=False)
user = register_form.save()
raw_password = register_form.cleaned_data.get('password1')
user = authenticate(request, email=user.email, password=raw_password)
group = Group.objects.get(name='Student')
user.groups.add(group)
if user is not None:
login(request, user)
return redirect('login')
return render(request, 'apps/register.html', {'register_form': register_form})

RegisterForm() missing 1 required positional argument: 'request'

So I'm making a custom user model. This is what I'am following Here. I have been pretty much following the tutorial but still I cant make it done.
Error: RegisterForm() missing 1 required positional argument: 'request'.
here's my code.
forms.py
from django import forms
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from .models import User
class UserAdminCreationForm(forms.ModelForm):
"""
A form for creating new users. Includes all the required
fields, plus a repeated password.
"""
password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
class Meta:
model = User
fields = ('email',)
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super(UserAdminCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
class UserAdminChangeForm(forms.ModelForm):
"""A form for updating users. Includes all the fields on
the user, but replaces the password field with admin's
password hash display field.
"""
password = ReadOnlyPasswordHashField()
class Meta:
model = User
fields = ('email', 'password', 'active', 'admin')
def clean_password(self):
# Regardless of what the user provides, return the initial value.
# This is done here, rather than on the field, because the
# field does not have access to the initial value
return self.initial["password"]
class LoginForm(forms.ModelForm):
email = forms.EmailField(label='Email')
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = User
fields = ('email', 'password',)
widgets = {
'email' : forms.EmailInput(
attrs={'class':'form-control', 'place_holder': '', }),
'password' : forms.PasswordInput(
attrs={'class':'form-control' }),
}
class RegisterForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
password2 = forms.CharField(label='Confirm password', widget=forms.PasswordInput)
class Meta:
model = User
fields = ('email',)
def clean_email(self):
email = self.cleaned_data.get('email')
qs = User.objects.filter(email=email)
if qs.exists():
raise forms.ValidationError("email is taken")
return email
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
models.py
from django.db import models
from django.contrib.auth.models import (
BaseUserManager, AbstractBaseUser
)
class UserManager(BaseUserManager):
def create_user(self, email, full_name, password=None, is_staff=False, is_active=True, is_admin=False):
"""
Creates and saves a User with the given email and password.
"""
if not email:
raise ValueError('Users must have an email address')
if not full_name:
raise ValueError('Users must have an full name')
if not password:
raise ValueError('Users must have a password')
user = self.model(
email=self.normalize_email(email),
)
user.full_name = full_name
user.set_password(password)
user.staff = is_staff
user.admin = is_admin
user.active = is_active
user.save(using=self._db)
return user
def create_staffuser(self, email, password):
"""
Creates and saves a staff user with the given email and password.
"""
user = self.create_user(
email,
password=password,
)
user.staff = True
user.save(using=self._db)
return user
def create_superuser(self, email, full_name, password):
"""
Creates and saves a superuser with the given email and password.
"""
user = self.model(
email=self.normalize_email(email)
)
user.full_name = full_name
user.set_password(password)
user.full_name = full_name
user.staff = True
user.admin = True
user.save(using=self._db)
return user
# Create your models here.
class User(AbstractBaseUser):
email = models.EmailField(max_length=255, unique=True)
full_name = models.CharField(max_length=255, null=True, blank=True)
active = models.BooleanField(default=True) # to login
staff = models.BooleanField(default=False) # a admin user; non super-user
admin = models.BooleanField(default=False) # a superuser
created_date = models.DateTimeField(auto_now_add=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['full_name'] # Email & Password are required by default.
objects = UserManager()
def __str__(self):
return self.email
def get_full_name(self):
# The user is identified by their email address
return self.email
def get_short_name(self):
# The user is identified by their email address
return self.email
def has_perm(self, perm, obj=None):
"Does the user have a specific permission?"
# Simplest possible answer: Yes, always
return True
def has_module_perms(self, app_label):
"Does the user have permissions to view the app `app_label`?"
# Simplest possible answer: Yes, always
return True
#property
def is_staff(self):
"Is the user a member of staff?"
return self.staff
#property
def is_admin(self):
"Is the user a admin member?"
return self.admin
#property
def is_active(self):
"Is the user active?"
return self.active
class Account_type(models.Model):
name = models.CharField(max_length=50, null=True, blank=True)
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
account_type = models.ForeignKey(Account_type, on_delete=models.CASCADE)
register.html
from django.shortcuts import render, redirect
from . forms import RegisterForm, LoginForm
# Create your views here.
def RegisterForm(request):
if request.method == 'POST':
form = RegisterForm(request.POST)
if form.is_valid():
form.save()
else:
form = RegisterForm()
context = {
'form' : form
}
return render(request, 'account/register.html', context)
The view logic is simple as you can see. Just saving up the request into the database. The tutorial itself did not tell anything about the view for login and register.
So, What am I doing wrong here.
Thank you
The problem is that your view RegisterForm has the same name as your form, hence if you call RegisterForm in your view, it will resolve to the view function, and make a recursive call.
Normally (top-level) functions are written in snake_case, hence you can rewrite it to register_form, or even better register (since it is not a form at all):
from django.shortcuts import render, redirect
from . forms import RegisterForm, LoginForm
# Create your views here.
def register(request):
if request.method == 'POST':
form = RegisterForm(request.POST)
if form.is_valid():
form.save()
return redirect('some-view-name')
else:
form = RegisterForm()
context = {
'form' : form
}
return render(request, 'account/register.html', context)
Normally a successful POST request results in a redirect to implement the Post/Redirect/Get pattern [wiki]. So I strongly advise you to use redirect(..) [Django-doc] and replace some-view-name with the name of a view to which you want to redirect.

django cannot link a user model and a corresponding from to be used in a template for sign up

I have a custom user model subclassing AbstractBaseUser:
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=254, unique=True)
name = models.CharField(max_length=254)
username = models.CharField(max_length=254, blank=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
last_login = models.DateTimeField(null=True, blank=True)
date_joined = models.DateTimeField(auto_now_add=True)
USERNAME_FIELD = 'email'
EMAIL_FIELD = 'email'
REQUIRED_FIELDS = ['name']
objects = UserManager()
def __str__(self):
return self.email
def get_absolute_url(self):
return "/users/%i/" % (self.pk)
after migrating, I created a simple form for sign up which I am mapping two fields from the model: email and name like below:
class SignUpForm(ModelForm):
class Meta:
model = CustomUser
fields = ['name', 'email']
I then have the view to render a template to show the above fields as input fields:
class MyRegisterView(RegisterView):
def get(self, request):
form = SignUpForm()
return render(request, "registration.html", context={"form": form})
and in the template, I am simply doing:
<form method="post">
{% csrf_token %}
<h3>Sign Up</h3>
<div>
<label for="name">
<input id = "name" name = "name" class="textfield" type="text" value="" placeholder="Name">
</label>
</div>
<div>
<label for="email">
<input id = "email" name = "email" class="textfield" type="email" value="" placeholder="Email">
</label>
(also including passwords and so on)
The problem is that when I add the name field and then submit, the name field in the database is not getting populated (the email is and the user account is created... but without the name). Why is that?
below is my custom BaseUserManager that I am subclassing: ( could it be that I am missing something in the below Usermanager?)
class UserManager(BaseUserManager):
def _create_user(self, name, email, password, is_staff, is_superuser, **extra_fields):
if not email:
raise ValueError('Users must have an email address')
now = timezone.now()
email = self.normalize_email(email)
user = self.model(
name=name,
email=email,
is_staff=is_staff,
is_active=True,
is_superuser=is_superuser,
last_login=now,
date_joined=now,
**extra_fields
)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, name, email, password, **extra_fields):
return self._create_user(name, email, password, False, False, **extra_fields)
def create_superuser(self, name, email, password, **extra_fields):
user = self._create_user(name, email, password, True, True, **extra_fields)
user.save(using=self._db)
return user