Using django form wizard with allauth - python

Currently my user sign up process is implemented with allauth. Does anyone have any experience of how to make this a multipage process e.g. with form wizard from formtools?
forms.py (stored at users/forms.py)
class UserCreationForm1(forms.UserCreationForm):
error_message = forms.UserCreationForm.error_messages.update(
{
"duplicate_username": _(
"This username has already been taken."
)
}
)
username = CharField(label='User Name',
widget=TextInput(attrs={'placeholder': 'User Name'})
)
class Meta(forms.UserCreationForm.Meta):
model = User
fields = ['username', 'email', 'title', 'first_name', 'last_name', 'country', ]
field_order = ['username', 'email', 'title', 'first_name', 'last_name', 'country', ]
def clean_username(self):
username = self.cleaned_data["username"]
if self.instance.username == username:
return username
try:
User._default_manager.get(username=username)
except User.DoesNotExist:
return username
raise ValidationError(
self.error_messages["duplicate_username"]
)
class UserCreationForm2(forms.UserCreationForm):
class Meta(forms.UserCreationForm.Meta):
model = User
fields = ['occupation', 'password1', 'password2', 'terms']
field_order = ['occupation', 'password1', 'password2', 'terms']
def clean_terms(self):
is_filled = self.cleaned_data['terms']
if not is_filled:
raise forms.ValidationError('This field is required')
return is_filled
For the views.py i then have
SIGNUP_FORMS = [('0', UserCreationForm),
('1', UserCreationForm2)]
TEMPLATES = {'0': 'account/signup_1.html',
'1': 'account/signup_2.html'}
class SignupWizard(SessionWizardView):
def get_template_names(self):
return [TEMPLATES[self.steps.current]]
def done(self, form_list, **kwargs):
for form in form_list:
if isinstance(form, UserCreationForm):
print('form1')
user = form.save(self.request)
elif isinstance(form, UserCreationForm2):
userprofile = form.save(commit=False)
user = self.request.user
userprofile.user = user
userprofile.save()
print('form2')
return HttpResponseRedirect(settings.LOGIN_REDIRECT_URL)
What I find though is that after completing the first form and clicking to continue to the second the user is redirected to the inbuilt allauth login: at accounts/signup/
Does anyone have any advice?

Related

Django issue saving data to database

username is saving but information such as first_name, email and etc are not.
`from django.contrib.auth.models import User
from django.contrib.auth.password_validation import validate_password
from rest_framework import serializers
class RegisterSerializer(serializers.ModelSerializer):
email = serializers.CharField(required=True)
first_name = serializers.CharField(max_length=50, required=True)
last_name = serializers.CharField(max_length=50, required=True)
password = serializers.CharField(
write_only=True, required=True, validators=[validate_password])
password2 = serializers.CharField(write_only=True, required=True)
is_admin = serializers.BooleanField(default=False)
class Meta:
model = User
fields = ('username', 'first_name', 'last_name', 'email',
'password', 'password2', 'is_admin')
def validate(self, attrs):
if attrs['password'] != attrs['password2']:
raise serializers.ValidationError(
{"password": "Password fields didn't match."})
return attrs
def create(self, validated_data):
user = User.objects.create(
username=validated_data['username']
)
user.set_password(validated_data['password'])
user.save()
return user`
i have searched online for hours, but have not managed to make much progress. if someone could elaborate on my issue and explain what I have done wrong that would be greatly appreciated
Add all the fields that you need to create that exist in model inside create method
user = User.objects.create(
username=validated_data['username'],
first_name =validated_data['first_name'],
last_name =validated_data['last_name'],
# Add other fields here
)
You should also send other validated data's to creation line:
def create(self, validated_data):
user = User.objects.create(
username=validated_data['username'],
first_name=validated_data['first_name'], # <-- add here to all necessary parameters like this
)
user.set_password(validated_data['password'])
user.save()

Unknown field(s) (model) specified for User

I am build project ,when i run python manage.py makemigrations
i got this error
File "/mnt/c/Users/ZAKARIA/Desktop/project/Accounts/admin.py", line 45, in <module>
class UpdateUserForm(forms.ModelForm):
File "/mnt/c/Users/ZAKARIA/Desktop/project/env/lib/python3.8/site-packages/django/forms/models.py", line 327, in __new__
raise FieldError(message)
django.core.exceptions.FieldError: Unknown field(s) (is_staff) specified for User
** Here is my code for models.py**
import datetime
from django.core.mail import send_mail
from distutils.command.upload import upload
from django.db import models
from django.contrib.auth.base_user import AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin
from django.utils import timezone
from phonenumber_field.modelfields import PhoneNumberField
from .managers import UserManger
GENDER_MALE = "m"
GENDER_FEMALE = "f"
OTHER = "o"
GENDER_CHOICES = (
(GENDER_MALE, "Male"),
(GENDER_FEMALE, "Female"),
(OTHER, "Other"),
)
class User(AbstractBaseUser):
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
)
date_of_birth = models.DateField()
first_name = models.CharField(max_length=30, blank=True)
last_name = models.CharField(max_length=30, blank=True)
gender = models.CharField(max_length=1, choices=GENDER_CHOICES, blank=True)
picture = models.ImageField(
upload_to='images/users', null=True, verbose_name="")
is_active = models.BooleanField(default=True)
#is_staff = models.BooleanField(default=False)
phone = PhoneNumberField()
is_admin = models.BooleanField(default=False)
#credits =models.PositiveIntegerField(default=100)
linkedin_token = models.TextField(blank=True, default='')
expiry_date = models.DateTimeField(null=True, blank=True)
objects = UserManger()
USERNAME_FIELD = 'email'
REQURTED_FIELDS = []
def get_full_name(self):
full_name = '%S %s' % (self.first_name, self.last_name)
return full_name.strip()
def get_short_name(self):
return self.first_name
def __str__(self):
return self.email
def has_perm(self, prem, obj=None):
"Does the user have a specific permission?"
return True
def has_module_perm(self, app_label):
"Does the user have permissions to view the app `app_label`?"
return True
#property
def is_staff(self):
"Is the user a member of staff"
return self.is_admin
"""#property
def is_out_of_credits(self):
"Is the user out of credits"
return self.credits > 0
#property
def has_sufficient_credits(self,cost):
return self.credits - cost >= 0
"""
#property
def linkedin_signed_in(self):
return bool(self.linkedin_token) and self.expiry_date > timezone.now()
** Here is my code for manangers.py **
from django.contrib.auth.base_user import BaseUserManager
class UserManger(BaseUserManager):
use_in_migrations = True
def _create_user(self, email, phone, password, **extra_fields):
if not email:
raise ValueError('Users must hava an email address')
user = self.model(
email.self.normalize_email(email),
phone=phone,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, phone, email, password=None, **extra_fields):
extra_fields.setdefault('is_superuser', False)
return self._create_user(email, phone, password, **extra_fields)
def create_superuser(self, email, phone, password, **extra_fields):
extra_fields.setdefault('is_superuser', True)
if extra_fields.get('is_superuser') is not True:
raise ValueError('Superuser must hava is_superuser=True.')
return self._create_user(email, phone, password, **extra_fields)
** Here is my code for admin.py**
from pyexpat import model
import django
from django.contrib import admin
from django import forms
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from .models import User
class AddUserForm(forms.ModelForm):
"""
new User Form . Requires password confirmation.
"""
password1 = forms.CharField(
label='Password', widget=forms.PasswordInput
)
password2 = forms.CharField(
label='Confirm password', widget=forms.PasswordInput
)
class Meta:
model = User
fields = ('email', 'first_name', 'last_name', 'gender')
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 do not match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super().save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
class UpdateUserForm(forms.ModelForm):
"""
Update User Form ,Doesn't allow changing password in the Admin
"""
password = ReadOnlyPasswordHashField()
class Meta:
model = User
fields = (
'email', 'password', 'first_name', 'gender', 'last_name', 'is_active',
'is_staff'
)
def clean_password(self):
return self.initial["password"]
class UserAdmin(BaseUserAdmin):
form = UpdateUserForm
add_form = AddUserForm
list_display = ('email', 'first_name', 'last_name',
'gender', 'is_staff')
list_filter = ('is_staff',)
fieldsets = (
(None, {'fields': ('email', 'password')}),
('Personal info', {
'fields': ('first_name', 'last_name', 'gender')}),
('Permissions', {'fields': ('is_active', 'is_staff')}),
)
add_fieldsets=(
(
None,
{
'classes':('wide',),
'fields':(
'email','first_name', 'last_name', 'gender','password1','password2'
)
}
),
)
search_fields=('email','first_name','last_name')
ordering =('email','first_name','last_name')
filter_horizontal = ()
admin.site.register(User, UserAdmin)
** Here is my code for forms.py**
from django.contrib.auth import authenticate
from django.contrib.auth.forms import UserCreationForm
from Accounts.models import User
class UserRegistrationForm(UserCreationForm):
def __init__(self, *args, **kwargs):
UserCreationForm.__init__(self, *args, *kwargs)
self.fields['gender'].required = True
self.fields['first_name'].label = "First Name :"
self.fields['last_name'].label = "Last Name :"
self.fields['email'].label = "Email :"
self.fields['password1'].label = "Password"
self.fields['password2'].label = " Confirm Password"
self.fields['gender'].label = "Gender"
self.fields['phone'].label = "Phone"
self.fields['date_of_birth'].label = "Date Of Birth"
self.fields['first_name'].widget.attrs.update(
{
'placeholder': 'Enter First Name',
}
)
self.fields['last_name'].widget.attrs.update(
{
'placeholder': 'Enter Last Name',
}
)
self.fields['email'].widget.attrs.update(
{
'placeholder': 'Enter Email',
}
)
self.fields['password1'].widget.attrs.update(
{
'placeholder': 'Enter Password',
}
)
self.fields['password2'].widget.attrs.update(
{
'placeholder': 'Confirm Password',
}
)
self.fields['phone'].widget.attrs.update(
{
'placeholder': 'Enter Phone',
}
)
self.fields['date_of_birth'].widget.attrs.update(
{
'placeholder': 'Enter Date Of Birth',
}
)
class Meta:
model = User
fields = ['first_name', 'last_name', 'email', 'phone',
'password1', 'password2', 'gender', 'date_of_birth']
def clean_gender(self):
gender = self.cleaned_data.get('gender')
if not gender:
raise forms.ValidationError("Gender is required")
return gender
def save(self, commit=True):
user = UserCreationForm.save(self, commit=False)
user.role = "user"
if commit:
user.save()
return user
class UserLoginForm(forms.Form):
email = forms.EmailField(
widget=forms.EmailInput(attrs={'placeholder': 'Email', })
)
password = forms.CharField(
strip=False, widget=forms.PasswordInput(attrs={'placeholder': 'Password', }))
def clean(self, *args, **kwargs):
email = self.cleaned_data.get("email")
password = self.cleaned_data.get('password')
if email and password:
self.user = authenticate(email=email, password=password)
try:
user = User.objects.get(email=email)
except User.DoesNotExist:
raise forms.ValidationError("User Does not exist")
if not user.check_password(password):
raise forms.ValidationError("Password is not Match")
if not user.is_active:
raise forms.ValidationError("User is not Active")
return super(UserLoginForm, self).clean(**args, **kwargs)
def get_user(self):
return self.user
** Here is my code for views.py**
from django.shortcuts import render
from django.contrib import messages, auth
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseRedirect
from django.shortcuts import render, redirect, get_list_or_404
from django.urls import reverse, reverse_lazye
from matplotlib.style import context
from Accounts.forms import *
def get_success_urls(request):
"""
Handle Success Url After Login
"""
if 'next' in request.GET and request.GET['next'] != '':
return request.GET['netx']
else:
return reverse('jobs:home')
def user_registration(request):
"""
Handle user registration
"""
form = UserRegistrationForm(request.POST or None)
if form.is_valid():
form = form.save()
return redirect('Accounts:login')
context = {
'form': form
}
return render(request, 'accounts/user-registeration.html', context)
def user_logIn(request):
"""
Provides users to logIn
"""
form = UserLoginForm(request.POST or None)
if request.user.is_authenticated:
return redirect('/')
else:
if request.method == 'POST':
if form.is_valid():
auth.login(request, form.get_user())
return HttpResponseRedirect(get_success_urls(request))
context = {
'form': form,
}
def user_logOut(request):
"""
Provide the ability to logout
"""
auth.logout(request)
messages.success(request, 'You are Successfully logged out')
return redirect('Accounts:login')
I already took out all of the is_staff attribute in admin.py and still got an error.
Refactored it many times to check if the problem is in different areas of my code.
can any one help me to solve this problem
Double check this is correct:
fields = (
'email', 'password', 'first_name', 'gender', 'last_name', 'is_active',
'is_staff'
the is_staff field, is that an actual field of your user model ?

Custom fields in user model Django

I am using normal User model in Django to save my users. I would like to add first_name and last_name field, but I don't know how to extend my model and make it work. First and last name should be added in in register form (I use crispy forms).
register view
if request.method == "POST":
form = UserRegisterForm(request.POST)
if form.is_valid():
form.save() # save user to database
username = form.cleaned_data.get('username')
messages.success(request, f"User {username} succesfully created! You can login now!")
return redirect('login')
else:
form = UserRegisterForm()
return render(request, 'users/register.html', {'form': form})
register form
def __init__(self, *args, **kwargs):
super(UserRegisterForm, self).__init__(*args, **kwargs)
self.fields['password1'].label = "Hasło"
self.fields['password2'].label = "Powtórz hasło"
email = forms.EmailField()
name = forms.CharField(
label="Imię",
required=True,
max_length=30,
)
surname = forms.CharField(
label="Nazwisko",
required=True,
max_length=30,
)
class Meta:
model = User
fields = ['username', 'email', 'password1', 'password2', 'name', 'surname']
labels = {
'username': 'Nazwa użytkownika',
}
Django's User model [Django-doc] already has a first_name and last_name, you can subclass the UserCreationForm and add fields for the first_name and last_name:
from django.contrib.auth.forms import UserCreationForm
class UserRegisterForm(UserCreationForm):
def __init__(self, *args, **kwargs):
super(UserRegisterForm, self).__init__(*args, **kwargs)
self.fields['password1'].label = 'Hasło'
self.fields['password2'].label = 'Powtórz hasło'
email = forms.EmailField()
first_name = forms.CharField(
label='Imię',
required=True,
max_length=30,
)
last_name = forms.CharField(
label='Nazwisko',
required=True,
max_length=30,
)
class Meta:
model = User
fields = ['username', 'email', 'password1', 'password2', 'first_name', 'last_name']
labels = {
'username': 'Nazwa użytkownika',
}

How to restrict access for staff users to see only their information in Django admin page?

I have created a custom Django admin page. I have two types of users who can access admin page (staff user and superuser). Superuser can see all the users and can change their settings. He can also add or delete users. The staff user can only see their settings and can change some of them. I currently have a problem that staff users can see all users of the web application and can add or delete them. I restricted staff users to see certain settings but could not change it.
I do not know how to restrict staff users to see only their settings.
Here is my code:
Admin.py
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from .forms import UserAdminChangeForm, UserAdminCreationForm
from .models import UpLoadFile
User = get_user_model()
admin.site.site_header = 'SRC Orkestracija'
admin.site.index_title = 'Administration'
admin.site.register(UpLoadFile)
class UserAdmin(BaseUserAdmin):
# The forms to add and change user instances
form = UserAdminChangeForm
add_form = UserAdminCreationForm
# The fields to be used in displaying the User model.
# These override the definitions on the base UserAdmin
# that reference specific fields on auth.User.
list_display = ('username', 'superuser', 'active', 'staff')
list_filter = ('superuser', 'active', 'staff')
readonly_fields = [
'last_login'
]
actions = [
'activate_users',
]
filter_horizontal = ('user_permissions', 'groups')
fieldsets = (
(None, {'fields': ('username', 'password', 'config_file')}),
('Permissions', {'fields': ('superuser', 'active', 'staff', 'groups', 'user_permissions')}),
('Important dates', {'fields': ('last_login',)}),
)
# add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
# overrides get_fieldsets to use this attribute when creating a user.
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('username', 'password1', 'password2', 'config_file')}
),
)
search_fields = ('username',)
ordering = ('username',)
def get_form(self, request, obj=None, **kwargs):
form = super().get_form(request, obj, **kwargs)
is_superuser = request.user.is_superuser
disabled_fields = set()
if not is_superuser:
disabled_fields |= {
'username',
'active',
'superuser',
'staff',
'groups',
'user_permissions'
}
if (
not is_superuser
and obj is not None
and obj == request.user
):
disabled_fields |= {
'username',
'active',
'superuser',
'staff',
'groups',
'user_permissions'
}
for f in disabled_fields:
if f in form.base_fields:
form.base_fields[f].disabled = True
return form
def activate_users(self, request, queryset):
is_superuser = request.user.is_superuser
if is_superuser:
cnt = queryset.filter(active=False).update(active=True)
self.message_user(request, 'Activated {} users.'.format(cnt))
activate_users.short_description = 'Activate Users'
admin.site.register(User, UserAdmin)
Models.py:
class UserManager(BaseUserManager):
def create_user(self, username, config_file, password=None, is_active=True, is_staff=False, is_superuser=False):
if not username:
raise ValueError("User must have username!")
if not password:
raise ValueError("User must have password!")
if not config_file:
raise ValueError("Select config file!")
user_obj = self.model(
username=username,
)
user_obj.config_file = config_file
user_obj.staff = is_staff
user_obj.superuser = is_superuser
user_obj.active = is_active
user_obj.set_password(password)
user_obj.save(using=self._db)
return user_obj
def create_staffuser(self, username, config_file, password=None):
user = self.create_user(
username=username,
config_file=config_file,
password=password,
is_staff=True
)
return user
def create_superuser(self, username, config_file, password=None):
user = self.create_user(
username=username,
config_file=config_file,
password=password,
is_staff=True,
is_superuser=True
)
return user
class CustomUser(AbstractBaseUser, PermissionsMixin):
class Meta:
verbose_name = "User"
verbose_name_plural = "Users"
OPTIONS = (
('1', '1'),
('2', '2'),
('3', '3'),
('4', '4'),
)
username = models.CharField(unique=True, max_length=255)
active = models.BooleanField(default=True,
help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.')
staff = models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.')
superuser = models.BooleanField(default=False,
help_text='Designates that this user has all permissions without explicitly assigning them.')
config_file = models.CharField(choices=OPTIONS, max_length=255)
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['config_file']
object = UserManager()
def __str__(self):
return self.username
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_lable):
return True
#property
def is_staff(self):
return self.staff
#property
def is_superuser(self):
return self.superuser
#property
def is_active(self):
return self.active
def path(user, filename):
return os.path.join(str(user))
I will appreciate any help or instructions how can I add this feature.
You can set superusers to only have add/delete permissions in the admin class.
class UserAdmin(BaseUserAdmin):
...
def has_add_permission(self, request, obj=None):
return request.user.is_superuser
def has_delete_permission(self, request, obj=None):
return request.user.is_superuser
Note the above is also achievable by not granting the add or delete permissions to any group or user in the admin interface.
The following will only allow users to change all users if they are a superuser. Else they will only be able to change their own user.
def has_change_permission(self, request, obj=None):
return request.user.is_superuser or (obj and obj.id == request.user.id)
And if you want them to be able to see the user list page with only their user visible you can modify get_queryset
def get_queryset(self, request):
qs = super().get_queryset(request)
user = request.user
return qs if user.is_superuser else qs.filter(id=user.id)
In your template:
{% if request.user.is_superuser %}
<!-- Only superusers can view things in here -->
{% endif %}
In your view, you also will have to control what can be edited and what cannot be.

AttributeError: 'ReturnDict' object has no attribute 'pk'

I am trying to design an api for user login and logout. But I am facing an error of AttributeError: 'ReturnDict' object has no attribute 'pk'. What might be creating this error?
traceback in detail
File "/home/tushant/Projects/nepMart/account/api/views.py", line 61, in post
login(request, serializer.data)
File "/home/tushant/.virtualenvs/NepMart/lib/python3.5/site-packages/django/contrib/auth/__init__.py", line 102, in login
if _get_user_session_key(request) != user.pk or (
AttributeError: 'ReturnDict' object has no attribute 'pk'
Serializers.py
class UserLoginSerializer(ModelSerializer):
token = CharField(allow_blank=True, read_only=True)
username = CharField(required=False, allow_blank=True)
# email = EmailField(label='Email Address',required=False, allow_blank=True)
remember = BooleanField(default=True, help_text = ("If checked you will stay logged in for 3 weeks"))
class Meta:
model = User
fields = [
'username',
# 'email',
'password',
'remember',
'token',
]
extra_kwargs = {"password":
{"write_only": True}
}
views.py
class UserLoginAPIView(APIView):
permission_classes = [AllowAny]
serializer_class = UserLoginSerializer
def post(self, request, *args, **kwargs):
data = request.data
serializer = UserLoginSerializer(data=data)
if serializer.is_valid(raise_exception=True):
# new_data = serializer.data
print('request.data', request.data)
print('serializer.data',serializer.data)
login(request, serializer.data)
if data.get('remember'):
request.session.set_expiry(60 * 60 * 24 * 7 * 3)
else:
request.session.set_expiry(0)
return Response({
'detail': ('Logged in successfully'),
# TODO: maybe more user info in the request would have sense
'username': serializer.data.username
})
return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)
ifincase usercreation is needed
class UserCreateSerializer(ModelSerializer):
email = EmailField(label='Email Address')
email2 = EmailField(label='Confirm Email Address')
class Meta:
model = User
fields = [
'username',
'id',
'password',
'email',
'email2',
]
extra_kwargs = {"password":
{"write_only": True}
}
def create(self, validated_data):
print('validated_data',validated_data)
username = validated_data['username']
email = validated_data['email']
email2 = validated_data['email2']
password = validated_data['password']
user_obj = User(
username=username,
email=email
)
user_obj.set_password(password)
user_obj.save()
return validated_data
Before login you should use authenticate method. Like this:
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
# Redirect to a success page.
else:
# Return a 'disabled account' error message
...
else:
# Return an 'invalid login' error message.
...
Inside the Meta class within the serializer class UserLoginSerializer :
The fields should also contain the attribute id.
I tried this and this fixes the issue for me.
class UserLoginSerializer(ModelSerializer):
token = CharField(allow_blank=True, read_only=True)
username = CharField(required=False, allow_blank=True)
# email = EmailField(label='Email Address',required=False, allow_blank=True)
remember = BooleanField(default=True, help_text = ("If checked you will stay logged in for 3 weeks"))
class Meta:
model = User
fields = [
'username',
'id', // required
# 'email',
'password',
'remember',
'token',
]
Comment me down and ask for help, if this doesn't fix your issue.

Categories