i am a beginner in django. I am working on a project in which customer and companies have their own accounts the models.py is:
class Company_SignUp(models.Model):
comp_name = models.CharField(_('Company Name'), max_length=30)
email = models.EmailField(_('E-mail'), unique=True)
raise forms.ValidationError("This email address already exists.")
password1 = models.CharField(_('Password'), max_length=128)
password2 = models.CharField(_('Confirm Password'), max_length=30)
def __unicode__(self):
return smart_unicode(self.comp_name)
class Customer_SignUp(models.Model):
cust_name = models.CharField(_('Customer Name'), max_length=30)
email = models.EmailField(_('E-mail'), unique=True)
password1 = models.CharField(_('Password'), max_length=128)
password2 = models.CharField(_('Confirm Password'), max_length=30)
def __unicode__(self):
return smart_unicode(self.cust_name)
my forms.py is:
class Company(forms.ModelForm):
class Meta:
model = Company_SignUp
widgets = {
'password1': forms.PasswordInput(),
'password2': forms.PasswordInput(),
}
fields = ('email','password1','password2','comp_name')
def clean(self):
if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:
if self.cleaned_data['password1'] != self.cleaned_data['password2']:
raise forms.ValidationError(_("The two password fields did not match."))
elif len(self.cleaned_data['password1']) < 8:
raise forms.ValidationError(_("The password must be 8 characters long."))
return self.cleaned_data
class Customer(forms.ModelForm):
class Meta:
model = Customer_SignUp
widgets = {
'password1': forms.PasswordInput(),
'password2': forms.PasswordInput(),
}
def clean(self):
if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:
if self.cleaned_data['password1'] != self.cleaned_data['password2']:
raise forms.ValidationError(_("The two password fields did not match."))
elif len(self.cleaned_data['password1']) < 8:
raise forms.ValidationError(_("The password must be 8 characters long."))
return self.cleaned_data
how will i authenticate a company or a customer using their email and passwords.
i tried authenticate() but it doesn't work.
also how will i check during registration , the email address given already exists
ok now i created a backend which is:
from django.contrib.auth.models import User
from prmanager.models import Company_SignUp, Customer_SignUp
class EmailBackend(object):
def authenticate(self, username=None, password=None):
try:
o = Company_SignUp.objects.get(email=username, password1=password)
except Company_SignUp.DoesNotExist:
try:
o = Customer_SignUp.objects.get(email=username, password1=password)
except Customer_SignUp.DoesNotExist:
return None
return User.objects.get(email=o.email)
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
But now i cannot login to admin page using superuser credentials. what should i do
Models
Consider extending the User model from django.contrib.auth.models like so. If you don't want to do this, skip to the next section (Authentication).
from django.contrib.auth.models import User
class Customer(User):
# extra fields
The User model has common fields such as username,first_name,last_name,email, etc. You only need to specify any extra attributes your model may have.
The Django docs suggest extending AbstractBaseUser, which may work for you too.
Read more here: https://docs.djangoproject.com/en/1.7/topics/auth/customizing/#extending-the-existing-user-model
Authentication
For email-based authentication, you need to write your own authentication backend: https://docs.djangoproject.com/en/1.7/topics/auth/customizing/#writing-an-authentication-backend
Once you have that in place, you need to accept email / password and authenticate using authenticate and login.
from django.contrib.auth import authenticate, login
def my_view(request):
email = request.POST['email']
password = request.POST['password']
user = authenticate(email=email, 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.
The above snippet is from the docs and I have modified it to fit your use-case.
More about authentication in Django: https://docs.djangoproject.com/en/1.7/topics/auth/default/#how-to-log-a-user-in
Related
Basically what I have done so far is create a registration page where the user makes their username and password, then that password is stored in as a hashed password (md5 hasher). The problem I am having is logging in. The user inputs their username and password then the password is authenticated by using authenticate() method in django. The problem is that authenticate() is returning None instead of matching the user and password in the database. I dont know if this affects anything but I am using PostgreSQL.
models.py
class MyAccountManager(BaseUserManager):
def create_user(self, email,username,first_name,password= None):
if not email:
raise ValueError('User must have an email address')
if not username:
raise ValueError('User must have a username')
if not first_name:
raise ValueError('User must have a first name')
user= self.model(
email=self.normalize_email(email),
username= username,
first_name= first_name
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, username, first_name, password):
user= self.create_user(
email= self.normalize_email(email),
username=username,
first_name= first_name,
password= password,
)
user.is_admin= True
user.is_staff= True
user.is_superuser= True
user.save(using=self._db)
return user
class User(AbstractBaseUser, models.Model):
email = models.EmailField(verbose_name='email', max_length=60, unique=True)
username = models.CharField(max_length=30, unique=True)
date_joined = models.DateTimeField(auto_now_add=True, verbose_name='date joined')
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)
is_active = models.BooleanField(default=True)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
USERNAME_FIELD= 'username'
REQUIRED_FIELDS= ['email','first_name']
objects= MyAccountManager()
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
forms.py
class LoginForm(forms.Form):
username = forms.CharField(initial='' ,label='Username:',max_length=30)
password = forms.CharField(max_length=20, widget=forms.PasswordInput())
class Meta:
model = User
fields = ('username', 'password')
def clean(self):
cleaned_data = super(LoginForm, self).clean()
confirm_password = cleaned_data.get('password')
class SignUpForm(forms.ModelForm):
first_name = forms.CharField(required= True,initial='',max_length=20)
last_name = forms.CharField(required=True,max_length=30, initial='')
username = forms.CharField(max_length=30,initial='', required=True)
password = forms.CharField(max_length= 20, initial='', widget = forms.PasswordInput())
password2= forms.CharField(max_length=20, initial='',widget = forms.PasswordInput())
email = forms.EmailField(max_length=60, initial='',)
class Meta:
model = User
fields = ('first_name', 'last_name','username','password2','email')
def clean(self):
cleaned_data = super(SignUpForm,self).clean()
password = cleaned_data.get('password')
confirm_password = cleaned_data.get('password2')
if(password != confirm_password):
raise forms.ValidationError(
'Password and Confirm Password do not match.'
)
views.py
def signin_and_signup(request):
if request.method == 'POST':
logout(request)
sign_in = LoginForm(request.POST)
signup = SignUpForm(request.POST)
if 'sign-in-name' in request.POST:
if sign_in.is_valid():
username = request.POST.get('username')
password= request.POST.get('password')
user = authenticate(username= username, password= password)
if user:
return HttpResponse('success')
else:
return HttpResponse('fail')
elif 'sign-up-input-name' in request.POST:
if(signup.is_valid()):
user = signup.save(commit=False)
nonHashed = signup.cleaned_data['password']
varhash = make_password(nonHashed, None, 'md5')
user.set_password(varhash)
user.save()
else:
print("Ran3<------------")
signup = SignUpForm()
else:
sign_in = LoginForm()
signup = SignUpForm()
context = {'signin':sign_in, 'signup':signup}
return render(request, 'home.html', context)
Why are you substituting the user model that django provides if you have the same attributes?
This is done in case you want to extend or add new properties to the user, for example, license number, avatar, position.
Anyway, your authenticate() maybe doesn't work because you haven't registered your new model in settings.py.
AUTH_USER_MODEL = 'name_of_the_app.User'
I recommend that you take a look at the official documentation
https://docs.djangoproject.com/en/3.1/topics/auth/customizing/
Antoher thing it could be your authentication backend:
Try:
settings.py
AUTHENTICATION_BACKENDS = [
'name_of_the_app.admin.LoginBackend',
]
Where you want for example admin.py
from django.contrib.auth.backends import ModelBackend, UserModel
from django.db.models import Q
class LoginBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
try: # to allow authentication through phone number or any other field, modify the below statement
user = UserModel.objects.get(Q(username__iexact=username) | Q(email__iexact=username))
except UserModel.DoesNotExist:
UserModel().set_password(password)
except MultipleObjectsReturned:
return models.User.objects.filter(email=username).order_by('id').first()
else:
if user.check_password(password) and self.user_can_authenticate(user):
return user
def get_user(self, user_id):
try:
user = UserModel.objects.get(pk=user_id)
except UserModel.DoesNotExist:
return None
return user if self.user_can_authenticate(user) else None
As you can see, you can also login with the email
Model.py
class UserProfileInfo(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE,default='')
# user = models.OneToOneField(User, on_delete=models.CASCADE)
phone_no = models.CharField(max_length=13,unique=True)
registered = models.BooleanField(default=False)
spam = models.BooleanField(default=False)
def __str__(self):
return self.user.username
Serializer.py
class UserSerializer(serializers.ModelSerializer):
password = serializers.CharField()
class Meta():
model = User
fields = ('username','email','password')
class UserProfileSerializer(serializers.ModelSerializer):
class Meta():
model = UserProfileInfo
fields = ('phone_no',)
views.py
def register(request):
registered = False
if request.method == 'POST':
user_serializer = UserSerializer(data=request.POST)
profile_serializer = UserProfileSerializer(data=request.POST)
if user_serializer.is_valid() and profile_serializer.is_valid():
user = user_serializer.save()
user.set_password(user.password) #saving hash value of password
user.save()
profile = profile_serializer.save(commit=False)
profile.user = user
profile.registered = True
profile.save()
registered = True
else:
print(user_serializer.errors)
else:
user_serializer = UserSerializer
profile_serializer = UserProfileSerializer
return Response(request,'basic_app/registration.html',{
'user_serializer':user_serializer,
'profile_form':profile_form,
'registered':registered
})
def user_login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
print(username,password)
user = authenticate(username=username, password=password)
print(user)
if user:
if user.is_active:
login(request,user)
return render(request,'basic_app/search.html')
else:
return HttpResponse('Account not active!')
else:
# print(username,password)
return HttpResponse('Login credentials not correct!')
else:
return render(request,'basic_app/login.html')
Now I need to make changes to my views.py such that I can parallely populate the user and the profile model having one to one field. I was using the form which was working well but now I need to convert the code to rest API. Please help how I can keep the same functionality using the above serializer class. My aim is to register and login the user.
First, c method in the serializer like my simple code:
(I used to write this class in my REST project for register student)
class StudentRegistrationSerializer(serializers.ModelSerializer):
password = serializers.CharField(style={'input_type': 'password'}, required=True)
password2 = serializers.CharField(style={'input_type': 'password'}, required=True)
class Meta:
model = Student
fields = ['phone_number', 'password', 'password2', 'name', 'family']
extra_kwargs = {
'password': {'write_only': True}
}
def save(self, **kwargs):
phone_number = self.validated_data.get('phone_number')
name = self.validated_data.get('name')
family = self.validated_data.get('family')
password = self.validated_data.get('password')
password2 = self.validated_data.get('password2')
not_active = User.objects.filter(username=phone_number, is_active=False)
is_active = User.objects.filter(username=phone_number, is_active=True)
if password != password2:
raise serializers.ValidationError({'error': 'password not matched'})
if is_active:
raise serializers.ValidationError({'error': 'username already exist'})
if not_active:
raise serializers.ValidationError({'error': 'username already exist active your account'})
user = User(username=phone_number, password=password, is_active=False)
user.set_password(password)
user.save()
student = Student(phone_number=phone_number, user=user, name=name, family=family)
student.save()
return student
and return the saved object here is student
and I recommend you to use build-in LoginView in the third-party library like "rest_auth" this library handles Token
after installing "rest_auth" using :
pip install django-rest-auth
in the url file just import :
from rest_auth.views import LoginView
and use it without any complexity
I have created a website where the user will login with his email instead of username as Django does. So, I have created an AUTHENTIFICATION_BACKENDS:
class EmailBackend(object):
def authenticate(self, username=None, password=None, **kwargs):
try:
user = User.objects.get(email=username)
except User.MultipleObjectsReturned:
user = User.objects.filter(email=username).order_by('id').first()
except User.DoesNotExist:
return None
if getattr(user, 'is_active') and user.check_password(password):
return user
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
My form:
class UserRegisterForm(forms.ModelForm):
username = forms.CharField()
email = forms.EmailField()
age = forms.IntegerField()
password2 = forms.CharField()
password = forms.CharField()
class Meta:
model = User
fields = ['username', 'age', 'email', 'password', 'password2']
At this stage, the login with an email is Working perfectly. The problem starts when I try to register a user. In registration view:
form = UserRegisterForm(request.POST)
register a new user:
user = form.save(commit=False)
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user.set_password(password)
user.save()
user = authenticate(username=username, password=password)
login(request, user)
This is where the problem appears. it seems like user = authenticate(username=username, password=password) is trying to create an anonymous user. What am I doing wrong in my AUTHENTIFICATION_BACKENDS ??
I'm using Django 1.7 and am trying to authenticate a user with email instead of the provided Django auth user.
This is my models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
class MyUserManager(BaseUserManager):
def create_user(self, email, password=None):
if not email:
raise ValueError('Users must have an email address')
user = self.model(
email=MyUserManager.normalize_email(email),
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password):
user = self.create_user(email,
password=password,
)
user.is_admin = True
user.save(using=self._db)
return user
class MyUser(AbstractBaseUser):
"""
Custom user class.
"""
email = models.EmailField('email address', unique=True, db_index=True)
joined = models.DateTimeField(auto_now_add=True)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
def __unicode__(self):
return self.email
and this is a snippet from my views.py
def auth_view(request):
username = request.POST.get('username', '')
password = request.POST.get('password', '')
user = auth.authenticate(username=username, password=password)
if user is not None:
auth.login(request, user)
return HttpResponseRedirect('/')
else:
return HttpResponseRedirect('/invalid/')
def register_user(request):
if request.method == 'POST':
form = MyRegistrationForm(request.POST)
if form.is_valid():
print "Form is valid"
form.save()
return HttpResponseRedirect('/register_success/')
args = {}
args.update(csrf(request))
args['form'] = MyRegistrationForm()
return render_to_response('register.html', args, context_instance=RequestContext(request))
and finally, my forms.py
from django import forms
from django.contrib.auth.models import User
class MyRegistrationForm(forms.ModelForm):
"""
Form for registering a new account.
"""
email = forms.EmailField(widget=forms.EmailInput,label="Email")
password1 = forms.CharField(widget=forms.PasswordInput,
label="Password")
password2 = forms.CharField(widget=forms.PasswordInput,
label="Password (again)")
class Meta:
model = User
fields = ['email', 'password1', 'password2']
def clean(self):
"""
Verifies that the values entered into the password fields match
NOTE: Errors here will appear in ``non_field_errors()`` because it applies to more than one field.
"""
cleaned_data = super(MyRegistrationForm, self).clean()
if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:
if self.cleaned_data['password1'] != self.cleaned_data['password2']:
raise forms.ValidationError("Passwords don't match. Please enter both fields again.")
return self.cleaned_data
def save(self, commit=True):
user = super(MyRegistrationForm, self).save(commit=False)
user.set_password(self.cleaned_data['password1'])
if commit:
user.save()
return user
Whenever I try to register an account, I get an error 'NoneType' object has no attribute '_insert' from forms.py calling user.save and views.py calling form.save. I don't really know how to write the user.save, but I'd imagine that would fix both errors.
Can anyone help me?
look at forms.py imports
from django.contrib.auth.models import User
must import MyUser instead of that
same in
class Meta:
model = User
fields = ['email', 'password1', 'password2']
and add to MyUser class
objects = MyUserManage()
change to
class Meta:
model = MyUser
fields = ['email', 'password1', 'password2']
and settings.py must set:
AUTH_USER_MODEL = '<apppath>.MyUser'
I want to create my own form for user createion of django.contrib.auth.models.User in Django, but I cant find a good example. Can someone help me?
you want to create a form?
create a form say forms.py
from django.contrib.auth.models import User
from django import forms
class CreateUserForm(forms.Form):
required_css_class = 'required'
username = forms.RegexField(regex=r'^[\w.#+-]+$',
max_length=30,
label="Username",
error_messages={'invalid': "This value may contain only letters, numbers and #/./+/-/_ characters."})
email = forms.EmailField(label="E-mail")
password1 = forms.CharField(widget=forms.PasswordInput,
label="Password")
password2 = forms.CharField(widget=forms.PasswordInput,
label="Password (again)")
def clean_username(self):
existing = User.objects.filter(username__iexact=self.cleaned_data['username'])
if existing.exists():
raise forms.ValidationError("A user with that username already exists.")
else:
return self.cleaned_data['username']
def clean_email(self):
#if you want unique email address. else delete this function
if User.objects.filter(email__iexact=self.cleaned_data['email']):
raise forms.ValidationError("This email address is already in use. Please supply a different email address.")
return self.cleaned_data['email']
def clean(self):
if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:
if self.cleaned_data['password1'] != self.cleaned_data['password2']:
raise forms.ValidationError("The two password fields didn't match.")
return self.cleaned_data
create a view say views.py
def create_inactive_user(request):
if request.method=='POST':
frm=CreateUserForm(request.POST)
if frm.is_valid():
username, email, password = frm.cleaned_data['username'], frm.cleaned_data['email'], frm.cleaned_data['password1']
new_user = User.objects.create_user(username, email, password)
new_user.is_active = True # if you want to set active
new_user.save()
else:
frm=CreateUserForm()
return render(request,'<templatepath>',{'form'=frm})
it is better to use django-registration