Django not seeing Users in database? - python

I have a database and have the admin interface enabled. When I go to the admin interface and click on 'Users' there is one user whose username is ayman. I am following a tutorial done in a book called 'Packt Publishing, Learning Website Development with Django'. Now, in my urls.py, this is what I have.
urlpatterns = patterns('',
url(r'^admin/', include(admin.site.urls)),
url(r'^$', main_page),
url(r'^user/(\w+)/$', user_page),
)
In my views.py, this is my user_page
def user_page(request, username):
try:
user = User.objects.get(username=username)
except:
raise Http404(username +' not found.')
bookmarks = user.bookmark_set.all()
variables = {
'username': username,
'bookmarks': bookmarks
}
return render(request, 'user_page.html', variables)
I am using the generic User view to manage my users. When I go into the terminal and do
$python manage.py shell
and do
>>> from django.contrib.auth.models import User
>>> from bookmarks.models import *
>>> user = User.objects.get(id=1)
>>> user
<User: ayman>
>>> user.username
u'ayman'
as you can see, the username ayman Does exist. Now, going back to the URLs and the user_page view. In my web browser, I went to
127.0.0.1/user/ayman/
The urls.py should capture ayman and pass it as a parameter to user_page, right? It does, but the user_page view keeps raising the 404 error and it says ayman not found. So the username parameter in user_page is in fact ayman but it keeps failing the
user = User.objects.get(username=username)
even though ayman is a username in my database. Any idea why?

You are using a bare except clause, try except User.DoesNotExist. The bare except masks the real error, the missing import. Btw. there is also a shortcut for this:
from django.shortcuts import get_object_or_404
# ...
user = get_object_or_404(User, username=username)
The first argument is the model or a queryset, the following are all passed as keyword arguments to queryset.get()

Related

Is it possible to override LoginView in function based views, not as a class?

I understand that in order to override from django.contrib.auth.views.LoginView one has to use a subclass Class(LoginView) in views.py.
However, in my views.py I only have views declared with def my_view(request)
In old versions of Django I could just do
from django.contrib.auth.views import login, logout
def login_user(request):
result = login(request=request, template_name='Market/pages/login.html')
return result
What's the modern Django equivalent of this? The documentation has this example, that forces me rewrite the whole username/password logic into my view:
from django.contrib.auth import authenticate, login
def my_view(request):
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
# Redirect to a success page.
...
else:
# Return an 'invalid login' error message.
...
How can I use a view function (not class!) and still have the automatic managing of the submitted request?
You're missing the point. The reason behind the move to class-based views is that they are more configurable than function-based ones.
In this case, you don't even need to define your own view to get the result you want; you can just do it in the URL:
path('login/', views.LoginView.as_view(template_name='Market/pages/login.html'), name='login')

Session being set but not persisted

Problem
The django.contrib.auth.login function is succeeding, but the session does not seem to persist.
Code
I am creating my own set of functions to use with an AJAX client inside of my Django server.
I have the following code in urls.py:
from django.contrib.auth import authenticate, login
from django.conf.urls import url
from django.http import JsonResponse
import json
def auth_login(request):
username = json.loads(request.body)['username']
password = json.loads(request.body)['password']
user = authenticate(request, username=username, password=password)
if user is not None and user.is_active:
login(request, user)
return JsonResponse({}, status=200)
else:
return JsonResponse({}, status=400)
urlpatterns = [
url(r'auth/login/', auth_login, name='login')
]
Details
As mentioned above, the call to login() succeeds. request.session is being set properly, and I can access if from within auth_login. On subsequent requests, request.session does not exist and django.contrib.auth.get_user returns AnonymousUser.
(Possibly relevant) I am also using the seemingly-popular https://django-tenant-schemas.readthedocs.io/en/latest/. This urls.py file is in an application that is per-tenant, so the user is actually authenticating on tenantname.hostname.com/tenant/auth/login/.
The tenant's django_session table is being set correctly. For each attempted login, I can see session_key, session_data, and expire_data.
The cookie for tenantname.hostname.com is empty after attempted logins.
I'm just out of ideas as to what other things I could try to lead me to a solution.
Question(s)
Any thoughts as to why this session isn't actually saved into the cookie?
OR
Thoughts as to what else I could try that could lead me to a solution?

How to check django staff user first time login in admin panel?

I am working on a django project and I am using the default auth app for authentication.
I know that there is a last_login field in user model which stores the user's last login time.
When a staff user logs in first time into the admin panel, I want to check if last_login field is none & redirect him to the change password page.
Where should I put this check?
What I have tried so far:
I have tried to use a custom login form and override the default confirm_login_allowed method on it, but it seems like I can only raise a validation error to block login attempt using these.
I also tried using django.contrib.auth.signals.user_logged_in Signal but that also does not allow me to return a redirect response when last_login is None.
I want to know how I can return a redirect response after the user has been authenticated.
Customise Django admin using AdminSite and use login_form attribute to give the custom login form for the Admin login page.
admin.py
class MyAdminSite(AdminSite):
login_form = CustomAdminLoginForm
admin_site = MyAdminSite(name='myadmin')
admin_site.register(User)
admin_site.register(Group
urls.py
When overriding the Admin we have to get rid of Django default admin
from app.admin import admin_site
url(r'^admin/', admin_site.urls)
forms.py
AuthenticationForm have the confirm_login_allowed method use this to grant permission to login in or not login in.
class CustomAdminLoginForm(AuthenticationForm):
def confirm_login_allowed(self, user):
if user.last_login:
raise ValidationError(mark_safe('Hey first time user please reset your password here... test'), code='inactive')
Note: There is lot of edge cases you have to consider for this approach.
What if user not set the password in the first time and how you're going to handle second attempt..? This time last_long not None. Although date_joined comes rescue. last_login == date_joined
But What if the user not set the password in first day and comes next day ?
Edit:
You can use signal to check the logged in user and apply the config_login_allowed logic here...?
from django.contrib.auth.signals import user_logged_in
def change_password_first_time(sender, user, request, **kwargs):
# Your business logic here...
user_logged_in.connect(change_password_first_time)
Django admin is not that configurable. You should hook into its internal views. Login/logout views are inside Django AdminSite class (the one you usually access by admin.site). My implementation is a bit hacky but small:
Paste at the top of urls.py
from django.contrib import admin
from django.contrib.admin import AdminSite
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
class MyAdminSite(AdminSite):
def login(self, request, extra_context=None):
new_user = False
user = None
username = request.POST.get('username') # Hack to find user before its last_login set to now.
if username:
user = User.objects.filter(username=username).first()
if user:
new_user = user.last_login is None
r = super(MyAdminSite, self).login(request, extra_context)
if new_user and request.user == user and isinstance(r, HttpResponseRedirect): # Successful logins will result in a redirect.
return HttpResponseRedirect(reverse('admin:password_change'))
return r
admin.site = MyAdminSite()
If you want a cleaner solution I suggest to use a boolean inside user model instead of relying on last_login so you could just check request.user instead of my hack into request.POST.
You could read AdminSite.login and django.contrib.auth.views.login to see what is actually happening inside Django.
It was a big problem for me at once. I found a way to do it easy. Create a different variable to save the value of the users logged in data, when user is trying to login.
Below is my code:
if user.last_login is None:
auth.login(request,user)
return redirect(alertPassword)
# when user is login for the first time it will pass a value
else:
auth.login(request,user)
return redirect(moveToLogin)
def moveToLogin(request):
return render(request,"home.html")
def alertPassword(request):
first_login=True
return render(request,"home.html",{"first_login":first_login})
#it will pass a value to the template called first login is True
Then go to your template and add this:
{% if first_login==True%}
# Put anything you want to be done
# In my case I wanted to open a new window by using script.
<script>
window.open("popUpWindow")
</script>
{%endif%}

Getting User Object for forms.py

I have an app called profiles which just leverages the django-registration-redux module. I am trying to create a form that allows the user to edit it, with the information they already have in it, but it isn't showing up. I can get it to show up without the information, but not the profile information that already exists.
urls.py
from django.conf.urls import url
from profiles import views
urlpatterns = [
url(r'^(?P<username>[-\w]+)/$', views.single, name='profile_single'),
url(r'^(?P<username>[-\w]+)/edit/$', views.edit, name="profile_edit"),
]
views.py
def edit(request, username):
instance = Profile.objects.get(user=username)
# It would be good to have an in depth understanding of what the actual request module does
if request.user == instance.user:
form = ProductForm(request.POST or None, instance = instance)
if form.is_valid():
profile = form.save(commit=False)
profile.user = request.user
profile.slug = slugify(form.cleaned_data['title'])
profile.save()
return HttpResponseRedirect('/user/%s'%(user.username))
return render_to_response("profiles/edit.html", locals(), context_instance=RequestContext(request))
The error that I am recieving is:
Exception Value: invalid literal for int() with base 10: 'admin'
You need to check username field of User model.
To do that, replace the following line:
instance = Profile.objects.get(user=username)
with:
instance = Profile.objects.get(user__username=username)

How to allow users to change their own passwords in Django?

Can any one point me to code where users can change their own passwords in Django?
Django comes with a user
authentication system. It handles user
accounts, groups, permissions and
cookie-based user sessions. This
document explains how things work.
How to change Django passwords
See the Changing passwords section
Navigation to your project where manage.py file lies
$ python manage.py shell
type below scripts :
from django.contrib.auth.models import User
u = User.objects.get(username__exact='john')
u.set_password('new password')
u.save()
You can also use the simple manage.py command:
manage.py changepassword *username*
Just enter the new password twice.
from the Changing passwords section in the docs.
If you have the django.contrib.admin in your INSTALLED_APPS, you can visit: example.com/path-to-admin/password_change/ which will have a form to confirm your old password and enter the new password twice.
You can also just use the django.contrib.auth.views.password_change view in your URLconf. It uses a default form and template; supplying your own is optional.
This tutorial shows how to do it with function based views:
View file:
from django.contrib import messages
from django.contrib.auth import update_session_auth_hash
from django.contrib.auth.forms import PasswordChangeForm
from django.shortcuts import render, redirect
def change_password(request):
if request.method == 'POST':
form = PasswordChangeForm(request.user, request.POST)
if form.is_valid():
user = form.save()
update_session_auth_hash(request, user) # Important!
messages.success(request, 'Your password was successfully updated!')
return redirect('change_password')
else:
messages.error(request, 'Please correct the error below.')
else:
form = PasswordChangeForm(request.user)
return render(request, 'accounts/change_password.html', {
'form': form
})
Url file:
from django.conf.urls import url
from myproject.accounts import views
urlpatterns = [
url(r'^password/$', views.change_password, name='change_password'),
]
And finally, the template:
<form method="post">
{% csrf_token %}
{{ form }}
<button type="submit">Save changes</button>
</form>
Its without need to go to shell enter passwd and reenter passwd
python manage.py changepassword <username>
or
/manage.py changepassword <username>
Using shell
python manage.py shell
from django.contrib.auth.models import User
users=User.objects.filter(email='<user_email>')
#you can user username or etc to get users query set
#you can also use get method to get users
user=users[0]
user.set_password('__enter passwd__')
user.save()
exit()
urls.py:
urlpatterns = [
url(r'^accounts/', include('django.contrib.auth.urls')),
Template:
{% trans "Change password" %}
Documented at: https://docs.djangoproject.com/en/1.9/topics/auth/default/#using-the-views
Per the documentation, use:
from django.contrib.auth.hashers import makepassword
The main reason to do this is that Django uses hashed passwords to store in the database.
password=make_password(password,hasher='default')
obj=User.objects.filter(empid=emp_id).update(username=username,password=password)
I used this technique for the custom user model which is derived from the AbstractUser model. I am sorry if I technically misspelled the class and subclass, but the technique worked well.
Authentication is the one way and after that reset the password
from django.contrib.auth import authenticate
user = authenticate(username='username',password='passwd')
try:
if user is not None:
user.set_password('new password')
else:
print('user is not exist')
except:
print("do something here")
Once the url pattern is added as shown in Ciro Santilli's answer, a quick way to allow users to change passwords is to give them "staff access" for the admin functions. If you don't add them to any groups or give them special permissions, they can still change their password by going to the example.com/admin page. The staff access lets them go to the page even if it is blank; in the upper right corner they can click "change password" and use the admin funtionality.
This is the command i used, just in case you are having problem in that throw AttributeError: Manager isn't available; 'auth.User' has been swapped for 'users.User'.
python manage.py shell -c "from django.contrib.auth import get_user_model;
User = get_user_model();
u = User.objects.get(username='admin');
u.set_password('password123');
u.save()"
Very similar to #Ciro's answer, but more specific to the original question (without adding all the authentication views):
just add to urlpatterns in urls.py:
url('^change-password/$', auth_views.password_change, {'post_change_redirect': 'next_page'}, name='password_change'),
Note that post_change_redirect specifies the url to redirect after the password is changed.
Then, just add to your template:
Change Password
view.py
views.py
def changepassword(request):
if request.method == "POST":
user_id = request.POST['user_id']
oldpassword = request.POST['oldpassword']
newpassword = request.POST['newpassword']
user = User.objects.get(id=user_id)
if **user.check_password**(oldpassword):
**user.set_password(newpassword)**
user.save()
return redirect("app:login-user")
else:
messages.success(request,"Pervious Password Not Match")
return redirect("app:changepassword")
else:
return render(request,'app/changepassword.html')
url.py
path('changepassword',views.changepassword,name='changepassword'),

Categories

Resources