django.contrib.auth.logout in Django - django

I would like to use the logout function from Django but not sure how to use it properly.I have been referring to this Django User Authenication: https://docs.djangoproject.com/en/dev/topics/auth/ and it reads
from django.contrib.auth import logout
def logout_view(request):
logout(request)
# Redirect to a success page.
The confusing part for me is the # Redirect to a success page. How do i redirect it to another page. Should I use HttpResponseRedirect or add additional arguments to logout(request). I am not sure what to do.. Need some guidance.

Django has a shortcut method called redirect. You could use that to redirect like this:
from django.contrib.auth import logout
from django.shortcuts import redirect
def logout_view(request):
logout(request)
return redirect('home')
Where home is the name of a url pattern you defined in urls.py like this:
urlpatterns = patterns('',
url(r'^$', 'blah.views.index', name='home'))
)
In the redirect call you could use a path as well, like / to redirect to the site root, but using named views is much cleaner.
PS: the code posted by #Hedde is from django.contrib.auth.views module, logout method. If that's what you want to use, you can import it like this:
from django.contrib.auth.views import logout

You don't have to write a view for that, you can just do:
(r'^accounts/logout/$', 'django.contrib.auth.views.logout',{'next_page': '/accounts/login'})
More info: https://docs.djangoproject.com/en/dev/topics/auth/default/#django.contrib.auth.views.logout

Look at the source of the logout method, it should give you a clear idea what's going on. You can add extra arguments to the logout method to handle redirecting, but you can also append after the method for custom behaviour
def logout(request, next_page=None,
template_name='registration/logged_out.html',
redirect_field_name=REDIRECT_FIELD_NAME,
current_app=None, extra_context=None):
"""
Logs out the user and displays 'You are logged out' message.
"""
auth_logout(request)
redirect_to = request.REQUEST.get(redirect_field_name, '')
if redirect_to:
netloc = urlparse.urlparse(redirect_to)[1]
# Security check -- don't allow redirection to a different host.
if not (netloc and netloc != request.get_host()):
return HttpResponseRedirect(redirect_to)
#etc...

def logout(request):
# Log out the user.
logout(request)
# Return to homepage.
return HttpResponseRedirect(reverse('registeration:index'))

urlpatterns =[
path('accounts/logout/', views.LogoutView.as_view(template_name="post_list.html"), name='logout'),
]
write a template_name as above inside it worked for me.Hope it might be useful.
Thankyou

Related

django-allauth login_redirect page with username as slug

I am using Django 3.2 and django-allauth 0.44
I have set my LOGIN_REDIRECT_URL in settings.py as follows:
LOGIN_REDIRECT_URL = 'profile-page'
in urls.py, I have the following route defined:
path('accounts/profile/slug:username', AccountProfileView.as_view(), name='profile-page'),
When I log in, (unsurprisingly), I get the following error message:
NoReverseMatch at /accounts/login/
Reverse for 'profile-page' with no arguments not found. 1 pattern(s) tried: ['accounts/profile/(?P[-a-zA-Z0-9_]+)$']
How do I pass (or specify) a parameter of the logged in user's username to the route?
If your view needs to perform redirects which are not very simple, you need to override the get_success_url method, considering that you use django-allauth, you will need to override allauth.account.views.LoginView and also write your own url pattern for it so that your overriden view is used. First override the view:
from django.urls import reverse
from allauth.account.views import LoginView as AllauthLoginView
from allauth.account.utils import get_next_redirect_url
class LoginView(AllauthLoginView):
def form_valid(self, form):
self.user = form.user # Get the forms user
return super().form_valid(form)
def get_success_url(self):
ret = (
get_next_redirect_url(self.request, self.redirect_field_name)
or reverse('profile-page', kwargs={'username': self.user.username})
)
return ret
Next wherever you define the urls for allauth, just add your own url before it:
from path_to.view_above import LoginView # Change this import properly
urlpatterns = [
...
path('accounts/login/', LoginView.as_view(), name="account_login"),
path('accounts/', include('allauth.urls')),
...
]
Another alternative solution using allauth is to use a custom ACCOUNT_ADAPTER and override it's get_login_redirect_url because LoginView will internally call it in case there is no next parameter. To do this, first inherit from allauth.account.adapter.DefaultAccountAdapter:
from django.urls import reverse
from allauth.account.adapter import DefaultAccountAdapter
class MyAccountAdapter(DefaultAccountAdapter):
def get_login_redirect_url(self, request):
return reverse('profile-page', kwargs={'username': request.user.username})
Next in settings.py set ACCOUNT_ADAPTER:
ACCOUNT_ADAPTER = "path.to.MyAccountAdapter"
The LOGIN_REDIRECT_URL should point to the page on which user lands after he successfully logs into your website, unless he was redirected to the login page by trying to visit any of the pages that require the authorization.
If you want to redirect user to a specific page, in this example to his own profile page, you can create an intermediate URL that will redirect the user to his own profile page, when visited. It can be accomplished like so:
Using class-based views:
class CurrentUserProfileRedirectView(LoginRequiredMixin, RedirectView):
def get_redirect_url(self, *args, **kwargs):
return reverse('profile-page', kwargs={'username': request.user.username})
or using function-based views:
#login_required
def current_user_profile(request):
return redirect('profile-page', username=request.user.username)
Next, register this redirect view as a regular view, not requiring any parameters, and set the LOGIN_REDIRECT_URL to this view's name.

Django - NoReverseMatch at /<url>/ after login

I'm using django-allauth for user authentication. After login the user must be redirected to /hello/prehome/.'hello' is the name of my app and the view for prehome redirects the user to homepage view along with a user id. I've specified the mentioned url in settings.py file under LOGIN_REDIRECT_URL. However, when I sign in with a registered username and password, I keep getting the error-
NoReverseMatch at /hello/prehome/
Reverse for 'homepage' with arguments '(None,)' and keyword arguments '{}' not found. 1 pattern(s) tried: ['hello/homepage/(?P<user_id>[0-9]+)/$']
...
/app/hello/views.py in prehome
return HttpResponseRedirect(reverse('homepage',args=(user.id,)))
When I register a new user, the page is redirected normally to homepage but the 'else' section of the homepage view is executed.
Following are snippets from the project-
views.py
def register(request):
if request.POST:
form=RegistrationForm(request.POST)
if form.is_valid():
username=form.cleaned_data['username']
password=form.cleaned_data['password']
email=form.cleaned_data['email']
user=User.objects.create_user(username=username,password=password,email=email)
user.save()
user=auth.authenticate(username=username,password=password)
if user.is_active:
auth.login(request,user)
return HttpResponseRedirect(reverse('homepage',args=(request.user.id,)))
else:
form=RegistrationForm()
return render(request,'hello/registration/register.html',{'form':form,})
def prehome(request):
user=request.user
return HttpResponseRedirect(reverse('homepage',args=(user.id,)))
def homepage(request,user_id):
user=User.objects.get(id=user_id)
if request.user.is_authenticated():
if request.user.is_active:
return render(request,'hello/userprofile/homepage.html',{'user':user,})
else:
return render(request,'hello/userprofile/error.html')
urls.py (in app's subdirectory)
from django.conf.urls import include, url
from . import views
urlpatterns=[
url(r'^prehome/$',views.prehome,name='prehome'),
url(r'^homepage/(?P<user_id>[0-9]+)/$',views.homepage,name='homepage'),
]
urls.py(in project folder)
from django.conf.urls import include, url
from django.contrib import admin
admin.autodiscover()
from hello import views
urlpatterns = [
url(r'^$',views.index,name='index'),
url(r'^admin/',include(admin.site.urls)),
url(r'^accounts/',include('allauth.urls')),
url(r'^hello/',include('hello.urls')),
]
Please help.
It was probably a syntactical error.I changed the return statement from return HttpResponseRedirect(reverse('homepage',args=(request.user.id,))) to return HttpResponseRedirect(reverse('homepage',args=[request.user.id])) and it worked.However, I do not understand where did it go wrong and why did it work after incorporating this change. The official django documentation uses the previous format of passing a parameter to a function.
You must be logged in, because None is not matched by regexp.

Django - how to implement an example.com/username url system

I am trying to implement on my website a simple and friendly address system.
What i'm thinking about is when the user logged in, his username will be displayed in the address bar.
www.example.com/username1 (for home page profile)
www.example.com/username1/about/
www.example.com/username1/gallery/
www.example.com/username2 (for home page profile)
www.example.com/username2/about/
www.example.com/username2/gallery/
And additionally if anyone enter the address www.example.com/username1, will be shown the profile of user1.
I already implemented a register/Login system using Django-Allauth
mySite/urls.py
url(r'^accounts/', include('allauth.urls')),
home/urls.py
url(r'^$', views.index),
home/views.py
def index(request):
return render_to_response('home/index.html', context_instance=RequestContext(request))
I tried to follow some examples like Facing problem with user profile url scheme like example.com/username in django
But i dont have this thing working yet. I dont understand what to do :(
Please, give some advise.
Add the following url as the last item of the mySite/urls.py:
urlpatterns = patterns('',
...
url(r'^(?P<username>\w+)/', include('userapp.urls')),
)
Then the username parameter will be passed to the views of your userapp:
userapp/urls.py:
from userapp import views
urlpatterns = patterns('',
url(r'^$', views.profile, name='user_profile'),
url(r'^about/$', views.about, name='user_about'),
url(r'^gallery/$', views.gallery, name='user_gallery'),
)
userapp/views.py:
def profile(request, username):
user = get_object_or_404(User, username=username)
return render(request, 'userapp/profile.html', {'profile_user': user})
def about(request, username):
...
def gallery(request, username):
...
It's almost perfect, but i have a bug. Let me explain. When i login (my login system is: django-allauth) on the http://127.0.0.1:8000/accounts/login/ i return to http://127.0.0.1:8000 with an error 404.
I am not getting the http://127.0.0.1:8000/username/ with the template, when the login botton is clicked.
The instalation of django-allauth require adding to the settings.py
LOGIN_REDIRECT_URL = '/'
How can i redirect to http://127.0.0.1:8000/username/ and show the correct template?
1. Regarding
How can i redirect to
Based on the answer from https://stackoverflow.com/a/20143515/4992248
# settings.py:
ACCOUNT_ADAPTER = 'project.your_app.allauth.AccountAdapter'
# project/your_app/allauth.py:
from allauth.account.adapter import DefaultAccountAdapter
class AccountAdapter(DefaultAccountAdapter):
def get_login_redirect_url(self, request):
return 'request.user.username' # probably also needs to add slash(s)
Would be better to use get_absolute_url, ie return 'request.user.get_absolute_url'. In this case you need to do:
# 1. Add `namespace` to `yoursite/urls.py`
urlpatterns = patterns('',
...
url(r'^(?P<username>\w+)/', include('userapp.urls', namespace='profiles_username')),
)
# 2. Add the code below to the Users class in models.py
def get_absolute_url(self):
# 'user_profile' is from the code shown by catavaran above
return reverse('profiles_username:user_profile', args=[self.username])
2. Regarding
show the correct template
catavaran wrote correct urls which leads to views.profile, so in view.py you need to write:
from django.shortcuts import render
from .models import UserProfile # import model, where username field exists
from .forms import UserProfileForm # import Users form
def profiles(request, username):
user = get_object_or_404(UserProfile, username=username)
return render(request, 'home/profiles.html', {'user_profile_form': user})
In template (i.e. profiles.html) you can show user's data via {{user_profile_form.as_p}}

Redirect if already logged in through Django urls?

Currently I use these patterns to log in and out
urlpatterns += patterns("",
(r'^login/$', 'django.contrib.auth.views.login', {'template_name': 'login.html'}),
(r'^logout/$', 'django.contrib.auth.views.logout', {'template_name': 'logout.html'})
)
Inspite of having LOGIN_REDIRECT_URL = '/profile/' in my settings.py, Django does not send me to /profile/ if I want to access /login/ when I'm already logged in...
Can I somehow redirect in the URL patterns of the auth system? I'm reluctant to write a custom view for that.
I use something like this in my urls.py:
from django.contrib.auth.views import login
from django.contrib.auth.decorators import user_passes_test
login_forbidden = user_passes_test(lambda u: u.is_anonymous(), '/')
urlpatterns = patterns('',
url(r'^accounts/login/$', login_forbidden(login), name="login"),
How about riding the Django login view?
Then add this little piece of code in that view:
if request.user.is_authenticated():
# Redirect to profile
If you want to do something else in template itself for the register user:
{% if user.is_authenticated %}
I ended up writing a decorator for such task.
Please take note that I've made it quick & dirty.
from django.conf import settings
from django.shortcuts import redirect
def redirect_if_logged(f=None, redirect_to_url=None):
u"""
Decorator for views that checks that the user is already logged in, redirecting
to certain URL if so.
"""
def _decorator(view_func):
def _wrapped_view(request, *args, **kwargs):
if request.user.is_authenticated():
redirect_url = redirect_to_url
if redirect_to_url is None:
# URL has 'next' param?
redirect_url_1 = request.GET.get('next')
# If not, redirect to referer
redirect_url_2 = request.META.get('HTTP_REFERER')
# If none, redirect to default redirect URL
redirect_url_3 = settings.LOGIN_REDIRECT_URL
redirect_url = redirect_url_1 or redirect_url_2 or redirect_url_3
return redirect(redirect_url, *args, **kwargs)
else:
return view_func(request, *args, **kwargs)
return _wrapped_view
if f is None:
return _decorator
else:
return _decorator(f)
Looking at the source code on Github, the default login view provided by django.contrib.auth will only use LOGIN_REDIRECT_URL if the login form is submitted via a POST request, and it has no next parameter. (The docs mention this too).
The login view doesn't actually do any checking of whether you're authenticated already or not - so an already-authenticated user hitting the page with a standard GET request will see the login form again - just the same as an unauthenticated user.
If you want different behaviour, I'd recommend writing your own login view.
On your projects urls.py file (url_patterns list), add redirect_authenticated_user=True as a parameter in login path like this:
path('admin/', admin.site.urls),
path('login/', auth_views.LoginView.as_view(
template_name='blog_app/login.html',
redirect_authenticated_user=True
), name='login'),
You could use this decorator
def login_excluded(redirect_to):
""" This decorator kicks authenticated users out of a view """
def _method_wrapper(view_method):
def _arguments_wrapper(self, request, *args, **kwargs):
if self.request.user.is_authenticated:
return redirect(redirect_to)
return view_method(request, *args, **kwargs)
return _arguments_wrapper
return _method_wrapper

django LOGIN_REDIRECT_URL with dynamic value

I'm trying to redirect a user to a url containing his username (like http://domain/username/), and trying to figure out how to do this. I'm using django.contrib.auth for my user management, so I've tried using LOGIN_REDIRECT_URL in the settings:
LOGIN_REDIRECT_URL = '/%s/' % request.user.username # <--- fail..
but it only seems to accept fixed strings, rather than something that'll be determined after the user is logged in. How can I still accomplish this?
A solution, is to redirect to a static route like '/userpage/' and have that redirect to the final dynamic page.
But I think the real solution is to make a new view that does what you really want.
from django.contrib.auth import authenticate, login
from django.http import HttpResponseRedirect
def my_view(request):
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)
HttpResponseRedirect('/%s/'%username)
else:
# Return a 'disabled account' error message
else:
# Return an 'invalid login' error message.
http://docs.djangoproject.com/en/dev/topics/auth/#authentication-in-web-requests
for more information about rewriting the view. This is how the docs say to override this kind of thing.
With the class-based django.contrib.auth.views.LoginView, you can now simply override get_success_url:
urls.py:
url(r'^login$', MyLoginView.as_view(), name='login'),
url(r'^users/(?P<username>[a-zA-Z0-9]+)$', MyAccountView.as_view(), name='my_account'),
views.py
class MyLoginView(LoginView):
def get_success_url(self):
return reverse('my_account', args=[self.request.user.username])
Wrap the auth view in your own custom view and redirect to wherever you want if authentication succeeded.
from django.http import HttpResponseRedirect
from django.contrib import auth
from django.core.urlresolvers import reverse
def login(request):
template_response = auth.views.login(request)
if isinstance(template_response, HttpResponseRedirect) and template_response.url == '/accounts/profile/':
return HttpResponseRedirect(reverse('user', args=(request.user.username,)))
return template_response
Another alternative is to use the query param next to indicate where to redirect to after the login.
sign in
I use django-two-factor-auth login view which provides OTP features for login.
Hence I extend from two_factor's LoginView.
In main urls.py:
from two_factor.urls import urlpatterns as tf_urls
urlpatterns = [
# make sure login is before default two_factor (tf_urls) urls
# coz first url has higher preference
path('account/login/', MyLoginView.as_view(), name='login'),
path('', include(tf_urls)),
]
In views.py:
from two_factor.views.core import LoginView
from two_factor.utils import default_device
class MyLoginView(LoginView):
def get_success_url(self):
if self.is_otp_setup() is True:
return reverse('homepage:homepage')
# otp not setup. redirect to OTP setup page
else:
return reverse('two_factor:setup')
def is_otp_setup(self):
if self.request.user and \
self.request.user.is_authenticated and \
default_device(self.request.user):
return True
else:
return False