In django is it the only way to have only one view for one whole page/url. And whatever functions(upload/post/update/log-in) that page contains just needs to pass inside that view. I found this is the only way as i can only return one url with one view.
I am wondering if there has any way where i can make different view(may be classed base or normal) for each function and at last add all of them on one single view(that view return that url also). If it is possible than how ? Because having all the functions of a url inside one view is looking weird and messy to me.
##################
def logInRegisterUser(request):
###################login##################
loginForm = UserLoginForm(request.POST or None)
if loginForm.is_valid() and 'log-in' in request.POST:
username = loginForm.cleaned_data.get("username")
password = loginForm.cleaned_data.get("password")
user = authenticate(username = username, password = password)
# if not user or not user.check_password(password):
# raise validation error
login(request, user)
print(request.user.is_authenticated())
###################registration###################
registrationForm = RegistrationForm(request.POST or None)
if registrationForm.is_valid() and 'sign-up' in request.POST:
user2 = registrationForm.save(commit = False)
password2 = registrationForm.cleaned_data.get('password')
user2.set_password(password2)
user2.save()
new_user = authenticate(username = user2.username, password = password2)
login(request, new_user)
###################log-out###################
###################search-post###################
####################voting-post##################
context = {
"loginForm":loginForm,
"registrationForm":registrationForm,
"re":request.POST
}
###################return###################
return render(request,"enter.html",context)
you can merge the response from another class. You can merge multiple class response into to a single view.
Django - Having two views in same url
Related
I am a beginner in Django and I am working on a project which requires Custom user model as I Don't require is_staff, is_superuser, is_admin.
So, but searching and other ways I made my own Custom user model. But it is not working and I am stuck on it for days.
It will be a huge help if someone can help me with the code.
settings.py
AUTH_USER_MODEL = 'accounts.Usermanagement'
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
'accounts.backends.EmailAuthBackend',
]
backends.py
#backends.py
# from django.contrib.auth.models import User
from django.contrib.auth.hashers import check_password
from django.contrib.auth import get_user_model
Usermanagement = get_user_model()
class EmailAuthBackend:
def authenticate(self,request,username=None,password=None):
print(request)
try:
user = Usermanagement.objects.get(emailid=username)
print(password)
print(user.password)
# print(check_password(password))
# print(user.check_password(password))
if user.check_password(password):
return user
return None
except user.DoesNotExist:
return None
def get_user(self,user_id):
try:
return user.objects.get(pk=user_id)
except user.DoesNotExist:
return None
views.py
# views.py
def loginPage(request):
# POST
if request.method == 'POST':
form = AuthenticationForm(request,data=request.POST)
# loginPage.html the html tag has attribute name = username for email ,
# name = password for password
if form.is_valid(): # Form Valid
email = request.POST['username']
password = request.POST['password']
#Check
print("EMAIL: ",email)
print("PASSWORD: ",password)
# Authentication USER
user = authenticate(request,username=email,password=password)
print("Authenticated ",user) # Check
# check
print(user)
if user is not None: # If User found
login(request,user,backend='accounts.backends.EmailAuthBackend')
messages.info(request, f"You are now logged in as {email}.")
return redirect("home")
else: # If User Not found
messages.error(request,"User not found")
return HttpResponse("User not found, not able to login")
else: # Form InValid
messages.error(request,"Invalid username or password.")
return HttpResponse("Form Invalid")
# GET
else:
form = AuthenticationForm()
context = {"form":form}
return render(request,"loginPage.html",context=context)
urls.py and other configurations are correct.
Problems:
check_password : always False
In DB I have unencrypted password ( ex:- password=admin )
DB is a legacy(existing) DB , so I first made the DB and then I did "python manage.py inspectdb" , which created models for me and then I changed few things, but did not changed the field names or the db_table name.
I am very much ok to create user through SHELL.
In loginPage.html the html tag has attribute name = username for email , name = password for password
if any other requirements I will edit the Questions
i think you cannot use the check_password function in your case, because it has been created for encrypted password case. Just make a user.password == password in your EmailAuthBackend
For second problem with get_user(), I think your userId is not the primary key for Django maybe, problem probably can be solved by filter directly by userId:
def get_user(self, user_id):
try:
return user.objects.get(userId=user_id)
except User.DoesNotExist:
return None
Concerning the problem No.2
Remove the password=password in your user=self.model()
It's making it difficult to make reference to the password in your user.set_password()
I want to use django's default password reset view "PasswordResetView" which let's the user reset his password when he forgets it in a template that already has a view that i built on my own, after looking at the tutorials and the questions i found how to use it only on a different template that is made only for the password reset, but i don't want the user to go to a different page just to change his password when he forgets it, i want to make it in a bootstrap modal in the home page.
here is my home view that i want to add PasswordResetView functionality to it:
def home(request):
user = request.user
signin_form = SigninForm()
signup_form = SignupForm()
if request.method == "POST":
if 'signin_form' in request.POST:
signin_form = SigninForm(request.POST)
if signin_form.is_valid():
email = request.POST['email']
password = request.POST['password']
user = authenticate(email=email, password=password)
if user:
login(request, user)
elif user is None:
messages.error(request, 'ُEmail or password is incorrect')
if 'signup_form' in request.POST:
signup_form = SignupForm(request.POST)
if signup_form.is_valid():
signup_form.save()
full_name = signup_form.cleaned_data.get('full_name')
email = signup_form.cleaned_data.get('email')
raw_password = signup_form.cleaned_data.get('password1')
account = authenticate(email=email, password=raw_password)
login(request, account)
context = {'signin_form': signin_form,'signup_form': signup_form}
return render(request, 'main/home.html', context)
PS: i tried copy pasting the source code of that view (PasswordResetView) from django's source code in my view but i found some errors because it's a class based view, so if you find this the proper way, guide me to do it
or if i can't merge them somehow how to create a custom one
this is what i found in the other answers which lets you use it in a certain template that has only that view (PasswordResetView) which is not what i want:
from django.contrib.auth import views as auth_views
path('password_reset/', auth_views.PasswordResetView.as_view(template_name="myapp/mytemplate.html",form_class=mypasswordresetform),name="reset_password"),
I'll give you a simple approach to having a password reset feature on your django application. Before having any code, let me give a brief exlanation of the process. What you want to do is get a user to input their email, check if there is any user with that email, then if there is one, send an email to that address with a uniquely generated link.
From this link, you should be able to extract the user object which you need to change password. An example would be to use django's signing module. This link will simply need to redirect the user to a template where there is a form with 2 fields i.e. New Password and Verify Password.
Django's generic views come with this functionality out-of-the-box if you are using Django's authentication module, but you aren't forced to use it, but its best to do so.
Here I'll only show you how to collect the email address on the same view as you said you wanted.
def home(request):
# ...your other code
if request.method == 'post':
if 'reset_password' in request.POST:
email = request.POST.get("email", "")
user_qs = User.objects.filter(email=email)
if not user_qs.exists():
# send error message to user here
else:
user = user_qs.get()
# send email with uniquely generated url here.
The other aspects of generating a URL and sending the mail, I believe you can research these separately. But I hope you now have an idea of where and what to search.
Django's authenticate function seems to always be returning none, ive already checked out this thread and updated the authentication backends in the settigns.py file.
This is the code that i am using to save the accounts being created:
if request.method == 'POST':
# Getting the information from the filled in UserCreationForm
user_form = UserCreationForm(data=request.POST)
# If the the form is valid then save the users data to the database
# hash the password using set_password and save the user again
# set registered to True
if user_form.is_valid():
user = user_form.save()
user.set_password(user.password)
user.save()
registered = True
# Invalid form or forms - mistakes or something else?
# Print problems to the terminal.
# They'll also be shown to the user.
else:
print user_form.errors
# Not a HTTP POST, so these forms will be blank, ready for user input.
else:
user_form = UserCreationForm()
# Render the template depending on the context.
return render_to_response(
'contracts/register.html',
{'user_form': user_form, 'registered': registered}, context)
This seems to be working, since after i create a new user on the site, the access database its linked to updates with that username and the encrypted password.
The user_from is created from UserCreationForm which is:
class UserCreationForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = User
fields = ('username','password','first_name','last_name','email','is_staff','is_active')
Here is the code in my user_login method which should be grabbing the username and password from the request and authenticating the combo
def user_login(request):
# context for the user's request.
context = RequestContext(request)
# form = AuthenticationForm()
# If the request is a HTTP POST
if request.method == 'POST':
# Gather the username and password provided by the user.
# This information is obtained from the login form.
user = request.user
userSubmit = user.username
passSubmit = user.password
#username = request.POST.get['username']
#password = request.POST.get['password']
user = authenticate(username = userSubmit, password=passSubmit)
#try:
# user = authenticate(username=userSubmit, password=passSubmit)
#except LockedOut:
# messages.error(request, 'You have been locked out because of too many login attempts. Please try again in 10 minutes.')
# If we have a User object, the details are correct.
# If None (Python's way of representing the absence of a value), no user
# with matching credentials was found.
else:
if user:
# Is the account active? It could have been disabled.
if user.is_active:
# If the account is valid and active, we can log the user in.
# We'll send the user back to the homepage.
login(request, user)
return redirect('home')
else:
# An inactive account was used - no logging in!
messages.error(request, 'Your account is disabled.')
else:
messages.error(request, 'The credentials you entered are invalid.')
# Bad login details were provided. So we can't log the user in.
# The request is not a HTTP POST, so display the login form.
# This scenario would most likely be a HTTP GET.
# No context variables to pass to the template system, hence the
# blank dictionary object...
return render_to_response('administrative/login.html', {'form': form}, context)
I'm a little bit confused on how Django's views work. I thought it worked this way:
User pressed a button on a html page
The action is linked to a view, so it goes to the function as defined in the url.py, and then it does some logic.
However below I have an index.html page that will redirect the user to a login page if the user is NOT logged in:
def index(request):
if not request.user.is_authenticated():
return redirect('/login.html')
else:
result = Hello_World.delay()
somethingDownByCelery = result.get(timeout=2)
context = {'somethingDownByCelery': somethingDownByCelery, 'userName': request.user.username}
return render(request, 'webapp/index.html', context)
Then I have a login.html, I have a logger that records users behaviors on each of the webpage.
def loginUser(request):
logger = logging.getLogger('views.logger.login')
try:
username = request.POST['username'];
logger.info("User:" + username + " in Login Page");
except:
logger.error("Cannot Identify User");
type = ""
try:
type = request.POST['submit']
logger.info("User:" + username + " requests:" + type);
except MultiValueDictKeyError:
logger.error("Cannot Identify User's Request");
try:
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
return redirect('index.html')
else:
return redirect('disabled.html')
else:
condition = "Invalid Login"
context = {'condition': condition}
return render(request, 'webapp/login.html', context)
except MultiValueDictKeyError:
context = None
return render(request, 'webapp/login.html', context)
The problem is that when the webpage is refreshed, or redirected to, it will get two logger.error in the two exceptions when I'm trying to request POST with username and submit, because I thought the behavior was 1(press the button in the webpage) then 2(run the function in views).
However, somehow it goes through the whole function first then generate a webpage, which is a 3 step procedure?
When Django executes a redirect, it executes the code for that view first, before rendering the actual page. Your code is executing loginUser(), and is triggering exceptions in both the first and second try blocks, which causes your logger statements.
So assuming you're coming from index and are not authenticated, the process goes something like:
index()
redirect('/login.html') [this will call whatever view is mapped to that url; you may want to consider using the url resolution django offers]
loginUser()
return render(request, 'webapp/login.html', context)
create and return the html to the user
My email change form for users works, but I feel like my code is not written correctly. If I did it the way I have done below, I'd need a thousand else statements so that the page would return a response. Can someone tell me how I can make this more efficient/better? I'm not sure of the conventional way to do this
Views.py
def email_change(request):
form = Email_Change_Form()
if request.method=='POST':
form = Email_Change_Form(request.POST)
if form.is_valid():
if request.user.is_authenticated:
if form.cleaned_data['email1'] == form.cleaned_data['email2']:
user = request.user
u = User.objects.get(username=user)
# get the proper user
u.email = form.cleaned_data['email1']
u.save()
return HttpResponseRedirect("/accounts/profile/")
else:
return render_to_response("email_change.html", {'form':form}, context_instance=RequestContext(request))
I would suggest a complete change on how you looked at this. In my opinion, you should have all the implementation on the form side.
forms.py
I've implemented a class based on the SetPasswordForm that is more complete:
class EmailChangeForm(forms.Form):
"""
A form that lets a user change set their email while checking for a change in the
e-mail.
"""
error_messages = {
'email_mismatch': _("The two email addresses fields didn't match."),
'not_changed': _("The email address is the same as the one already defined."),
}
new_email1 = forms.EmailField(
label=_("New email address"),
widget=forms.EmailInput,
)
new_email2 = forms.EmailField(
label=_("New email address confirmation"),
widget=forms.EmailInput,
)
def __init__(self, user, *args, **kwargs):
self.user = user
super(EmailChangeForm, self).__init__(*args, **kwargs)
def clean_new_email1(self):
old_email = self.user.email
new_email1 = self.cleaned_data.get('new_email1')
if new_email1 and old_email:
if new_email1 == old_email:
raise forms.ValidationError(
self.error_messages['not_changed'],
code='not_changed',
)
return new_email1
def clean_new_email2(self):
new_email1 = self.cleaned_data.get('new_email1')
new_email2 = self.cleaned_data.get('new_email2')
if new_email1 and new_email2:
if new_email1 != new_email2:
raise forms.ValidationError(
self.error_messages['email_mismatch'],
code='email_mismatch',
)
return new_email2
def save(self, commit=True):
email = self.cleaned_data["new_email1"]
self.user.email = email
if commit:
self.user.save()
return self.user
This class checks both if the e-mail have in fact changed (very useful if you need to validate the e-mail or update mail chimp for example) and produce the appropriate errors, so they are helpful for the user in the form view.
views.py
Your code adapted to my class:
#login_required()
def email_change(request):
form = EmailChangeForm()
if request.method=='POST':
form = EmailChangeForm(user, request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect("/accounts/profile/")
else:
return render_to_response("email_change.html", {'form':form},
context_instance=RequestContext(request))
As you can see the view is simplified, assuring everything on the form level.
To ensure the login I set a decorator (See the docs).
Ps: I changed email1 and email2 to new_email1 and new_email2 to be consistent with the Django approach on passwords. I also changed the form Email_Change_Form to EmailChangeForm according to Python guidelines for classes.
I would suggest moving the validation to the form clean method:
#form
class EmailChangeForm():
..
..
def clean(self):
if self.cleaned_data.get('email1', None) != self.cleaned_data.get('email1', None):
raise forms.ValidationError('Validation Failed')
#login_required('/login/') //You can check the user is logged in using the decorator
def email_change(request):
form = Email_Change_Form()
if request.method=='POST':
form = Email_Change_Form(request.POST)
if form.is_valid():
user = request.user //Don't know why you want to get the object from database when you already have it
user.email = form.cleaned_data['email1']
user.save()
return HttpResponseRedirect("/accounts/profile/")
else:
return render_to_response("email_change.html", {'form':form}, context_instance=RequestContext(request))
Update:
Doing this is redundant:
user = request.user
u = User.objects.get(username=user.username)
Because user is going to be the same as u i.e. user = u
You will create more complicated code with nested if, if you write every bit of logic in your views. You need to break them in appropriate sections. Like, for every form related validations, do it in forms like -
if `email1` is same as `email2`,
and if email1 is valid
check it in your form. You should check that in clean or clean_FieldName methods. Refer here: https://docs.djangoproject.com/en/dev/ref/forms/validation/#cleaning-and-validating-fields-that-depend-on-each-other
Another check you applied for authentication - if the user is authenticated or not. In this case, can a Unauthorised user change his email - well no. So why should I let my code run for it. It would be better to check this condition as soon as possible and then send the user to login page. #login_required is used to check this condition as a decorator of your view. See here : https://docs.djangoproject.com/en/dev/topics/auth/#the-login-required-decorator
If you really want to check your user authentication in your view, I think the good approach would be -
def email_change(request):
if not request.user.is_authenticated:
// Do what you need to say to user or send them to login
// return HttpResponse object / HttpResponseRedirect
form = Email_Change_Form(request.POST)
if request.method=='POST':
if form.is_valid():
...
else:
... // Display form.