I am new the Django and I am unable to save the Registration form using the Class Based View. I have made the Abstract user in the Models as shown below.
models.py
class User(AbstractBaseUser):
email = models.EmailField(max_length=255, unique=True)
full_name = models.CharField(max_length=255, blank=True, null=True)
active = models.BooleanField(default=True) # can login
staff = models.BooleanField(default=False) # staff user non superuser
admin = models.BooleanField(default=False) # superuser
timestamp = models.DateTimeField(auto_now_add=True)
user_type = models.CharField(max_length= 120, choices=u_type)
# confirm = models.BooleanField(default=False)
# confirmed_date = models.DateTimeField(default=False)
USERNAME_FIELD = 'email' #username
# USERNAME_FIELD and password are required by default
REQUIRED_FIELDS = [] #['full_name'] #python manage.py createsuperuser
objects = UserManager()
def __str__(self):
return self.email
def get_full_name(self):
if self.full_name:
return self.full_name
return self.email
def get_short_name(self):
return self.email
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
#property
def is_staff(self):
return self.staff
#property
def is_admin(self):
return self.admin
#property
def is_active(self):
return self.active
I have used Form for creating the Registration form as shown below
forms.py
class RegistrationForm(forms.Form):
password1 = forms.CharField(label='password')
password2 = forms.CharField(label='Confirm Password')
user_email = forms.CharField(label='Email')
full_name = forms.CharField(label='Full Name')
class Meta:
model = User
fields = ('full_name', 'email','user_type')
def clean_password2(self):
password1 = self.cleaned_data.get('password1')
password2 = self.cleaned_data.get('password2')
if password1 and password2 and password1 != password2:
raise forms.ValidationError('password does not match')
return password2
def save(self, commit=True):
user = super(RegistrationForm, self).save(commit=False)
user_mail = self.cleaned_data.get('user_email')
print(user_mail)
user.set_password(self.cleaned_data['password1'])
if(commit):
user.save()
return user
this is the view file for the form
views.py
class RegisterView(FormView):
form_class = RegistrationForm
template_name = 'register.html'
success_url='/login'
def form_valid(self,form):
request = self.request
# f = JobForm(request.POST)
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
print(form)
instance = form.save(commit=False)
return redirect('/')
The issue I am facing is when I am trying to save the registration form then it is giving me the error 'super' object has no attribute 'save'. Currently I am struggling to save the form using the Class Based View.
Related
I am building a Django app. I have customized the User model. My models.py:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from phonenumber_field.modelfields import PhoneNumberField
from phonenumber_field.phonenumber import PhoneNumber
# Create your models here.
class UserManager(BaseUserManager):
def create_user(self, phone_number,username,email=None, password=None):
if not phone_number:
raise ValueError("You must specify your phone number")
if not username:
raise ValueError("You must specify your username")
try:
user = self.model(phone_number= PhoneNumber.from_string(phone_number=phone_number,region="BD").as_national,
username=username,
email=self.normalize_email(email))
except :
user = self.model(phone_number= PhoneNumber.from_string(phone_number=phone_number,region="BD").as_national,
username=username)
user.save(using=self._db)
return user
def create_stuffuser(self, phone_number,username,email,password):
user = self.create_user(phone_number,username,email=email,password=password)
user.staff = True
user.save(using=self._db)
return user
def create_superuser(self, phone_number,username,email,password):
user = self.create_user(phone_number,username,email=email,password=password)
user.staff = True
user.admin= True
user.save(using=self._db)
return user
class User(AbstractBaseUser):
phone_number = PhoneNumberField(unique=True)
username = models.CharField(unique=False,max_length=50)
REQUIRED_FIELDS = ['username']
email = models.EmailField(unique=False)
is_active = models.BooleanField(default=True)
staff = models.BooleanField(default=False)
admin = models.BooleanField(default=False)
USERNAME_FIELD = 'phone_number'
def get_full_name(self):
return self.username
def get_short_name(self):
return self.username
def get_email(self):
return self.email
def __str__(self):
return str(self.phone_number)
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self,app_label):
return True
#property
def is_staff(self):
return self.staff
#property
def is_admin(self):
return self.admin
objects = UserManager()
I am logged in but it is throwing error.
My Ticket model:
User = settings.AUTH_USER_MODEL
class Ticket(models.Model):
from_station = models.CharField(max_length=30)
to_station = models.CharField(max_length=30)
purchased_on = models.DateTimeField(default=timezone.now)
travel_on = models.DateTimeField()
customer = models.ForeignKey(User,on_delete=models.CASCADE)
def __str__(self):
return f"Customer:{self.customer.username},From:{self.from_station},To:{self.to_station},Travel on:{self.travel_on},Purchased on:{self.purchased_on}"
My views.py:
#csrf_protect
#login_required
def buyticket(response):
if response.method == 'POST':
form = Ticket(response.POST)
if form.is_valid():
form.save()
return redirect('main-home-page')
else:
form = Ticket()
return render(response,'main/ticket.html',{'form':form})
The error I got:
Ticket has no customer.
Request Method: GET
Request URL: http://127.0.0.1:8000/ticket/
Django Version: 3.2.4
Exception Type: RelatedObjectDoesNotExist
Exception Value:
Ticket has no customer.
Exception Location: C:\Users\HP\AppData\Local\Programs\Python\Python39\lib\site-packages\django\db\models\fields\related_descriptors.py, line 197, in __get__
Python Executable: C:\Users\HP\AppData\Local\Programs\Python\Python39\python.exe
Python Version: 3.9.2
A user can have multiple tickets. But it is not taking any user. Whenever I am trying to go to ticket route it calls me to login. I do but then it throws this error.
This error shows to you cause You declare the from equal to model
in :
else:
form = Ticket()
You should create another file called forms.py in the app
and do something like that
from .models import Ticket
from django.forms import ModelForm
class TicketForm(ModelForm):
class Meta:
model = Ticket
fields = '__all__
and in views
from .forms import TicketForm
def buyticket(response):
form = TicketForm()
if response.method == 'POST':
if form.is_valid():
form.save()
return redirect('main-home-page')
else:
form = TicketForm()
return render(response,'main/ticket.html',{'form':form})
You can get more info in the docs
I have the following code in my register_view function. When I register a new user it updates in the database, but I want to check whether a user has already been authenticated by email or user.
I have tried request.user.is_authenticated but this always returns true, and the request body is always saving when I fire a new POST call.
#csrf_exempt
def register_view(request):
if request.POST:
form = RegistrationForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('username')
email = form.cleaned_data.get('email').lower()
raw_password = form.cleaned_data.get('password1')
account = authenticate(email=email, password=raw_password)
login(request, account)
return JsonResponse(f'User {email} : {username} has been registered.', status=200, safe=False)
else:
form = RegistrationForm()
return JsonResponse('You are missing some fields.', status=422, safe=False)
--> User Model
class User(AbstractBaseUser):
firstname = models.CharField(max_length=30)
lastname = models.CharField(max_length=30)
email = models.EmailField(verbose_name="email address", max_length=60, unique=True)
username = models.CharField(max_length=30, 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)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username', 'firstname', 'lastname']
class Meta:
db_table = "users"
def __str__(self):
return self.username
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, app_label):
return True
--> Registration Form
class RegistrationForm(UserCreationForm):
email = forms.EmailField(max_length=255, help_text="Email address required.")
firstname = forms.CharField(max_length=30, help_text="First name required.")
lastname = forms.CharField(max_length=30, help_text="Last name required")
class Meta:
model = User
fields = ('firstname', 'lastname', 'email', 'username', 'password1', 'password2')
def clean_email(self):
email = self.cleaned_data['email'].lower()
try:
user = User.objects.get(email=email)
except Exception as e:
return email
raise forms.ValidationError(f"Email {email} is already in use.")
def clean_username(self):
username = self.cleaned_data['username']
try:
user = User.objects.get(username=username)
except Exception as e:
return username
raise forms.ValidationError(f"Username {username} is already in use.")
Check request.user.is_authenticated in your view before you start saving the form. If it's true, then redirect the user to another page:
#csrf_exempt
def register_view(request):
if request.user.is_authenticated:
return redirect('url-to-some-other-page')
if request.method == 'POST':
# ... other code remains the same
My forms.py :
class UserLoginForm(forms.Form):
username = forms.CharField(widget=forms.TextInput(attrs=
{'class':'form-control form-control-lg','placeholder':'Username'}))
password = forms.CharField(widget=forms.PasswordInput(attrs=
{'class':'form-control form-control-lg','placeholder':'Password'}))
def clean(self, *args, **kwargs):
username = self.cleaned_data.get("username")
password = self.cleaned_data.get("password")
if username and password:
user = authenticate(username=username, password=password)
if user is None:
raise forms.ValidationError("This user does not exist")
elif user is not None:
if not user.is_active:
raise forms.ValidationError("This user is not longer
active.")
elif not user.check_password(password):
raise forms.ValidationError("Incorrect password")
return super(UserLoginForm, self).clean(*args, **kwargs)
models.py :
class User(AbstractUser):
is_client = models.BooleanField(default=False)
is_trainer = models.BooleanField(default=False)
username = models.CharField('username', max_length=150, unique=True)
email = models.EmailField(unique=True)
hub = models.ForeignKey(Hub, on_delete=models.CASCADE,blank=True,
null=True)
USER_POSITIONS = ((0, 'Not a member'), (1, 'Member'), (2, 'Excom'),
(3, 'Leader'))
hub_position = models.CharField(default='Not Member',max_length=50)
mentor = models.ForeignKey('self' ,on_delete=models.CASCADE,
blank=True,null=True)
terms = models.BooleanField(blank=True,default=False)
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email','terms']
def get_absolute_url(self):
return reverse('student:dashboard', kwargs={'pk': self.pk})
I want the user to be redirected to the resend activation link page if he hasnt activated already .Now after i register the user and skip account activation and then try to login ,it shows validation error "This user does not exist" eventhough this user is registered in the User model .
The problem lies with the version of Django that you're using.
The more recent versions of Django return users for any authentication, only if user.is_active=TRUE
My suggestion to solve this problem would be the use of CustomUserModel for your User.
I use something like this:
class User(AbstractBaseUser):
email = models.EmailField(db_index=True, unique=True, max_length=255)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
objects = UserManager()
def __str__(self):
return self.email
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
and add AUTH_USER_MODEL = 'myapp.User' in my settings.py
Basically, go for a CustomUserModel that suits your needs and that should do it.
I created MainUser model and this model has unicode method, but here I have problem like 'unicode' object is not callable
this my authorization function:
def auth(request):
params = dict()
if request.method == 'POST':
try:
login = request.POST['login']
password = request.POST['password']
except:
messages.add_message(request, messages.WARNING, 'empty fields')
return redirect(reverse('main:sing_in'))
user = authenticate(username=login, password=password)
if user is not None:
login(request, user)
return redirect('main:work')
else:
return redirect(reverse('main:sing_in'))
return render(request, 'sing_in.html', params)
and this one my mainuser model:
class MainUser(AbstractBaseUser, PermissionsMixin):
"""
django user model
"""
login = models.CharField(max_length=20, blank=False, unique=True,
db_index=True, verbose_name=u'Логин')
first_name = models.CharField(max_length=222, blank=True,
verbose_name=u'Имя')
second_name = models.CharField(max_length=222, blank=True,
verbose_name=u'Фамилия')
email = models.EmailField(max_length=100, blank=True, verbose_name=u'email')
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
objects = MainUserManager()
USERNAME_FIELD = 'login'
REQUIRED_FIELDS = []
def full(self):
return {
"first_name": self.first_name,
"second_name": self.second_name,
"email": self.email
}
#property
def is_staff(self):
return self.is_admin
def get_short_name(self):
return self.login
def get_full_name(self):
return u"{0} {1}".format(self.second_name, self.first_name)
def __unicode__(self):
return u"{}".format(self.login)
class Meta:
verbose_name = u"Пользователь"
verbose_name_plural = u"Пользователи"
I can't understand where bug in the code, it give error when i call login(request, user)
You've redefined login to be the variable that stores the data from your field. Call it something else.
I'm trying to create a new user in my Django app but nothing happens. I'm using a custom user auth model. Part of the code I edited from the docs. Why the error message "Users must have an email address" is reported by the model and not the forms? Why am I not able to create a user? I don't get any error back.
My model:
from django.db import models
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser
from django.utils import timezone
class MyUserManager(BaseUserManager):
def create_user(self, email, name, neighborhood, password=None):
if not email:
raise ValueError('Users must have an email address')
user = self.model(
email=self.normalize_email(email),
name=name,
neighborhood=neighborhood
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, name, neighborhood, password):
user = self.create_user(
email=email,
name=name,
password=password,
neighborhood=neighborhood
)
user.is_admin = True
user.save(using=self._db)
return user
class MyUser(AbstractBaseUser):
name = models.CharField(max_length=255)
email = models.EmailField(max_length=255, unique=True)
created_at = models.DateTimeField(default=timezone.now, blank=True)
neighborhood = models.CharField(max_length=255)
consultant_id = models.IntegerField(null=True)
moip_id = models.IntegerField(null=True)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
objects = MyUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name', 'neighborhood']
def __str__(self):
return self.name
def get_full_name(self):
return self.name
def get_short_name(self):
return self.name
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
#property
def is_staff(self):
"Is the user a member of staff?"
# Simplest possible answer: All admins are staff
return self.is_admin
My form:
from django import forms
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from dashboard.models import MyUser
class UserCreationForm(forms.ModelForm):
password = forms.CharField(label='Senha', widget=forms.PasswordInput)
confirm_password = forms.CharField(label='Confirmar senha', widget=forms.PasswordInput)
class Meta:
model = MyUser
# Note - include all *required* MyUser fields here,
# but don't need to include password and confirm_password as they are
# already included since they are defined above.
fields = ('email', 'name', 'neighborhood',)
def clean(self):
cleaned_data = super(UserCreationForm, self).clean()
password = cleaned_data.get('password')
confirm_password = cleaned_data.get('confirm_password')
if password and confirm_password and password != confirm_password:
raise forms.ValidationError('As senhas nao batem.')
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data['password'])
if commit:
user.save()
return user
And my view:
from django.shortcuts import render
from frontend.forms import UserCreationForm
# Create your views here.
def register(request):
message = None
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
return render(request, 'frontend/register.html', {'message': message})
So far I know, you do not raise error from forms, you just -
1) add the error in it, then it automatically gets invalided by django and is posted back with error and also
2) since you are overriding the clean method you must return the cleaned data. So change the clean method with these details -
def clean(self):
cleaned_data = self.cleaned_data
password = cleaned_data.get('password')
confirm_password = cleaned_data.get('confirm_password')
if password and confirm_password and password != confirm_password:
#raise forms.ValidationError('As senhas nao batem.') => we do not raise error in form clean, instead we add it in validation error.
self.add_error('confirm_password', 'As senhas nao batem.')
return super(UserCreationForm, self).clean() # =>this line is IMPORTANT to not break the calling hierarchy
a little shorter -
def clean(self):
if self.cleaned_data['password'] != self.cleaned_data['confirm_password']:
self.add_error('confirm_password', 'Password & Confirm Password must match.')
return super().clean()
Sine you are not returning anything, the cleaned_data of your form is empty and thus django is returning you back to the form page with no data in it.