I'm having trouble with logout() while testing my project with the Django web server. This is my logout view:
def logout(request):
logout(request)
return render_to_response('main.html', {})
When I access /logout (which calls this view) I get a popup window that says Python crashed. It doesn't give me any trace in the console.
You have a slight problem of recursion there. logout is calling itself, and so on until you get a stack overflow.
Rename the view or the Django logout function when you import it.
The answer above says it all, but I find it helpful to rename external functions with some sort of unique prefix so you know where it's coming from, and because of this prefix, it will never conflict with your own functions. For example, if you're using django's logout function, you would have something like:
from django.contrib.auth import logout as auth_logout
def logout(request):
auth_logout(request)
return render_to_response('main.html', {})
Related
I'm learning Django. I created the Sign out function. But when I loop with for it gives an error.
My Code:
def logout(request):
for key in request.session.keys():
del request.session[key]
return redirect('login')
But get this error ? I am using Python 3. Can you help me ?
RuntimeError at /logout/
dictionary changed size during iteration
Modifying a collection over which you are iterating is tricky, and frequently not allowed. It can easily result in problems, since the iterator is usually implemented under the assumption that the collection will not change.
You however do not need to iterate over the keys here. You can use the clear() method [Django-doc]:
def logout(request):
request.session.clear()
return redirect('login')
This is however not sufficient. Django already made a function to logout a user that will clear the session, delete it, etc. logout(..) [Django-doc]. You thus can implement this as:
from django.contrib.auth import logout as auth_logout
def logout(request):
auth_logout(request)
return redirect('login')
I've burrowed through the mound of NoReverseMatch questions here on SO and elsewhere, but to no avail.
I have a view method, clean, and within in a redirect:
def clean(request, aid):
if request.method == 'POST':
return redirect(enrich,
permanent=True,
aid=account.id)
else:
return render(request, 'clean.html')
And a view method called enrich:
def enrich(request, aid):
return HttpResponse('this be the enrich page')
It has a path in urls.py:
path('<aid>/enrich/', views.enrich, name='enrich'),
And yet, when calling on the redirect in the clean method, I am lovingly told this by Python:
NoReverseMatch at /app2/<aid>/clean/
Reverse for 'app2.views.enrich' not found. 'app2.views.enrich' is not a valid view function or pattern name.
Which leaves me flummoxed, as app2.views.enrich does indeed exist. What am I to do? The path exists and operates correctly (if I visit /app2/<aid>/add/, I am welcomed with the proper HTTP response), but on redirect it doesn't actually seem to work, and neither do any of the other views.
Some context:
There are 3 apps in this Django project
All of these apps have proved functional along with their views
The versioning is Django 2.1 and Python 3.7.1
Disclaimer: the app is not actually called 'app2', that is simply a placeholder.
The wrong in this program is redirect(enrich, ...), the redirect first argument can't be a view function or view class.
ref from https://docs.djangoproject.com/en/2.1/_modules/django/shortcuts/#redirect:
The arguments could be:
A model: the model's get_absolute_url() function will be called.
A view name, possibly with arguments: urls.reverse() will be used
to reverse-resolve the name.
A URL, which will be used as-is for the redirect location.
The error message of Reverse for 'app2.views.enrich' not found, is because it print the view function's qualified name.
You should use str 'enrich' as first argument in redirect().
In the context of multiple apps, one has to specify the app namespace in the redirect.
return redirect('app2:enrich', ...
I'm trying to make a view restricted unless login is done. Was following tuts+plus django unchained tutorial
However login_required decorator somehow is not doing the job. What am I doing wrong?
that part at views.py (login_required has been imported)
#login_required
def story(request):
if request.method == "POST":
form = StoryForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/')
else:
form = StoryForm()
return render(request, 'stories/story.html', {'form': form})
no changes has been brought in urls.py. So I am hoping for an error where it can't find /login. But that somehow is not happening.
settings.py has LOGIN_URL = "/login/"
I'm not sure why this is happening. But for some reason in chrome the default story view is opening without redirecting to /login whereas it is working fine in Firefox. I tried clearing the cached images & files in Chrome, but it didn't help.
For now I'll just use Firefox to get through it.
I had the same issue. I cleared Chrome chache but it didn't work . Now i am running it on Firefox and its running correctly
Clear the page cookies via chrome DevTool -> Application -> Storage -> Cookies can fix this.
Add an entry in urls.py like this:
(r'^login/$', 'login_view'),
Or you can use remove LOGIN_URL = "/login/" from your settings.py and use:
#login_required(login_url='/login/')
in both case you must add entry to urls.py
Make sure your chrome browser has cleared all of the browsing data, mind that time range choice all time, and then you will solve this problem. I alse encountered this issue, after using Firefox to work well, I got it.
Alternatively, you can fix this error by just opening your app in Google Chrome's Incognito Window.
I had the same problem and I realized the browser identifies me as a logged-in user because I had logged in before as administrator in the admin page. I logged out of the admin page and the login_required decorator worked correctly.
I was able to resolve this by using the logout() function imported the same way as login() and that essentially "cleared" any existence of my already logged in user.
Make a logout view function/url route, run the app and call the url, then you will no longer be able to access the other view functions with the decorator unless logged in once again.
Question Clarification:
I'm trying to test if the user is authenticated or not for each page request.
I'm trying to use Authentication for the first time in Django and I am not grasping how the login view is supposed to handle authentications.
When I use #login_required, I'm redirecting to "/login" to check if the user is logged in and if not, display the login page. However, trying to redirect back to the original page is causing an infinite loop because it's sending me back to the login page over and over again.
I'm clearly not grasping how #login_required is supposed to work but I'm not sure what I'm missing. I've been searching around for awhile for an example, but everyone uses the default #login_required without the 'login_url' parameter.
So for example.. the page I'm trying to access would be...
#login_required(login_url='/login')
def index(request):
And then my login would be.. (obviously incomplete)..
Edit: just to note.. the session variables are set in another view
def login(request):
if '_auth_user_id' in request.session:
# just for testing purposes.. to make sure the id is being set
print "id:",request.session['_auth_user_id']
try:
user = Users.objects.get(id=request.session['_auth_user_id'])
except:
raise Exception("Invalid UserID")
# TODO: Check the backend session key
# this is what I'm having trouble with.. I'm not sure how
# to redirect back to the proper view
return redirect('/')
else:
form = LoginForm()
return render_to_response('login.html',
{'form':form},
context_instance=RequestContext(request)
)
Well, as you say, obviously that's not going to work, because it's incomplete. So, until you complete it, you're going to get an infinite loop - because you haven't written the code that puts _auth_user_id into request.session.
But I don't really know why you're making that test in the first place. The auth documentation has a perfectly good example of how to write a login view: get the username and password from the form, send them to authenticate to get the user object, then pass that to login... done.
Edit I think I might see where your confusion is. The login_required decorator itself does the check for whether the user is logged in - that's exactly what it's for. There's no need for you to write any code to do that. Your job is to write the code that actually logs the user in, by calling authenticate and login.
Try to call login(), see the next please:
https://docs.djangoproject.com/en/dev/topics/auth/#django.contrib.auth.login
I've noticed a strange behavior with how Django is processing my url patterns. A user should login and then be redirected to their profile page. I also have the ability for a user to edit their profile.
Here are my URL patterns for one of my apps:
urlpatterns=patterns('student.views',
(r'profile/$', login_required(profile,'student')),
(r'editprofile/$', login_required(editprofile,'student')),
)
This is for an app called student. If the user goes to /student/profile they should get the profile view. If they go to /student/editprofile they should get the editprofile view. I setup a function called login_required which does some checks on the user. It's a little more complicated than I could handle with just annotations.
Here's login_required:
def login_required(view,user_type='common'):
print 'Going to '+str(view)
def new_view(request,*args,**kwargs):
if(user_type == 'common'):
perm = ''
else:
perm = user_type+'.is_'+user_type
if not request.user.is_authenticated():
messages.error(request,'You must be logged in. Please log in.')
return HttpResponseRedirect('/')
elif request.user.is_authenticated() and user_type != 'common' and not request.user.has_perm(perm):
messages.error(request,'You must be an '+user_type+' to visit this page. Please log in.')
return HttpResponseRedirect('/')
return view(request,*args,**kwargs)
return new_view
Anyways, the weird thing is that, when I visit /student/profile, even though I get to the right page, login_required prints the following:
Going to <function profile at 0x03015DF0>
Going to <function editprofile at 0x03015BB0>
Why is it printing both? Why is it trying to visit both?
Even weirder, when I try to visit /student/editprofile, the profile page is what loads and this is what's printed:
Going to <function profile at 0x02FCA370>
Going to <function editprofile at 0x02FCA3F0>
Going to <function view_profile at 0x02FCA4F0>
view_profile is a function in a completely different app.
These two patterns:
(r'profile/$', login_required(profile,'student')),
(r'editprofile/$', login_required(editprofile,'student')),
Both match http://your-site/student/editprofile.
Try:
(r'^profile/$', login_required(profile,'student')),
(r'^editprofile/$', login_required(editprofile,'student')),
Django uses the view who's pattern matches first (see number 3 here).
Not sure why you can't use the standard #login_required decorator - it seems that your version actually provides less functionality, given that it always redirects to \, rather than the actual login view.
In any case, the reason why both are printed is because the print statement is in the top level of the decorator, and thus is executed when the urlconf is evaluated. If you put it in the inner new_view function, it will only be executed when it is actually called, and should print only the relevant view name.
Your login_required looks like it's a python decorator. Any reason you need to have it in your urls.py?
I think the print 'Going to '+str(view) line is getting evaluated when urlpatterns is read to determine which view to execute. It looks weird, but I don't think it'll hurt you.
The line print 'Going to '+str(view) will not be executed every time the view is hit, only when the url pattern is evaluated (I think). The code in new_view is the only code that will execute for certain as part of the view.