Django logout() returns none - python

Morning everyone
Im using django logout() to end my sessions just like django docs says :
views.py
class Logout(View):
def logout_view(request):
logout(request)
return HttpResponseRedirect(reverse('cost_control_app:login'))
and im calling it from this url :
urls.py
url(r'^logout/$', views.Logout.as_view(), name = "logout"),
Buttttttt it's not working, when i do a trace i find that the function :
def logout_view(request):
it's returning "none" and it's nos entering to execute the code inside...
Please help me !

I'm curious, why do you have the method named logout_view()? By default, nothing is going to call that method. You need to change the name to match the HTTP verb which will be used to call the page. For instance, if it's going to be a GET request, you would change it to:
def get(self, request):
If you want it to be a POST request, you would change it to:
def post(self, request):
This is the standard way that class-based views work in Django. Also, you may want to look at the documentation for class-based views, as this may give you a better idea of their workings and what they can provide to you. (Hint: There is a built-in RedirectView)

Django has a built in logout view. I would use that rather than writing your own.
from django.contrib.auth import views as auth_views
from django.core.urlresolvers import reverse_lazy
url(r'^logout/$',
auth_views.logout,
{'next_page': reverse_lazy('cost_control_app:login')},
name='logout',
)
If you want to write your own logout view, then I would stick with a function based view. There's no need to use a class based view here. The docs on logging a user out have an example.
def logout_view(request):
logout(request)
# Redirect to a success page.
Then change the url pattern to
url(r'^logout/$', logout_view, name="logout"),
If you really want to write a class based view, then you need to fix your Logout view. See Joey's answer for more info about this.

Solved it, i just removed the class logout(View) and call the def from the url without the "as_view" and it works. Thanks to all !

Related

Passing context to django-registration's views

I'm utilizing django-registration with a set of premade templates I found on Github for doing a two-step (registration-activation) workflow using HMAC.
I want to pass global variables (defined in context-processors) like my website's name to the emails sent by django-registration. the activation email sent to a new registrant, for example, or the password change one.
The "problem" is I don't directly have access to those views. That's kinda the point of django-registration, you include its path in the urls.py file, and everything works:
urlpatterns = [
url(r'^', include('core.urls')),
url(r'^admin/', admin.site.urls),
url(r'^accounts/', include('registration.backends.hmac.urls')),
]
What's the minimum effort way of adding context to those views? I've already created and am successfully passing context to emails in my own views (using context processors):
def send_some_email_view(request):
msg_plain = render_to_string('email_change_email.txt', context, request=request)
msg_html = render_to_string('email_change_email.html', context, request=request)
But what about views I didn't create?
Edit: So I made some progress, finding django-registration's registration view, and this method inside of it:
def send_activation_email(self, user):
"""
Send the activation email. The activation key is simply the
username, signed using TimestampSigner.
"""
activation_key = self.get_activation_key(user)
context = self.get_email_context(activation_key)
context.update({
'user': user
})
subject = render_to_string(self.email_subject_template,
context)
# Force subject to a single line to avoid header-injection
# issues.
subject = ''.join(subject.splitlines())
message = render_to_string(self.email_body_template,
context)
user.email_user(subject, message, settings.DEFAULT_FROM_EMAIL)
I don't want to override it inside the source code because that would prevent me from updating. So now the question becomes: Is my only way out writing a view that subclasses this view, and overriding the method? This means I'm writing separate views for every view provided by django-registartion that needs to send an email...
First create your own view based on the vendor view and overwrite your desired method:
from registration.backends.hmac.views import RegistrationView
class CustomRegistrationView(RegistrationView):
def get_email_context(self, user):
context = super().get_email_context(user)
return RequestContext(self.request, context)
Than have a look at registration.backends.hmac.urls.py (source). They just define a bunch of urls there.
You can easily overwrite just one of them by adding your own before you include the one from the app.
from yourapp import views
urlpatterns = [
# [...]
url(r'^accounts/register/$', views.CustomRegistrationView.as_view(), name='registration_register'),
url(r'^accounts/', include('registration.backends.hmac.urls')),
# [...]
]
While changing just the necessary things you also get some insight of whats going on in your 3rd party app, which is always an advantage. This applies to most 3rd party apps not just the one you are currently using.
Here's what I ended up doing, Thanks to the direction dahrens' answer sent me to:
# myapp/processors.py
def get_website_name(request):
website_name = 'ExcitingWebsiteThatsComingSoon'
return {'mysite_name': website_name}
# some views.py file
from myapp.processors import get_website_name
class RegistrationViewWithContext(RegistrationView):
def get_email_context(self, user):
context = super().get_email_context(user)
context['req'] = get_website_name(self.request)
return context
Basically, I'm simply using my custom processor to inject the website's name. It isn't as clean as I hoped it would be: While in my templates I can simply use {{ mysite_name}}, in the email template I have to use {{req.mysite_name}}. But this does have the DRY-ness I aimed for: all templates updating accordingly if the variable in the function changes.
I'll mark my answer as correct for now and will update accordingly if any new answers come in.

Can you have two of the same regex but point to them to different url files

For example is the following allowed? If so, is it not recommended or is it okay?
urlpatterns = [
url(r'^$', include('login.urls')),
url(r'^$' include('register.urls')),
url(r'^admin/', admin.site.urls),
]
Yes, you can set it up in django, but the second one will not be used, because django will find the url from top to bottom, when it found the match record, django will return the first record and stop there, so, the second one could not have chance to execute.
No, Django will math the first regex.
But you can for example set one regex for one view
and than in that view do specific operations based on the type of the request (GET/POST/PUT etc)
class CommentView(View):
def get(self, request):
... do if get type
def post(self, request):
... do if post type
And also you can check in view if user is logged in or not, if not you can redirect them to login.

How do I redirect visitors to login page?

I have the following url handler in my main Django project urls.py:
url(r'^$', 'core.views.generic.index')
Instead of landing on the index page as above, I want users to land on the login page.
I have another urls.py in an app called core that sends visitors to the login page:
url(r'^/login$', private.MeLogin.as_view())
How can I send all the people visiting url(r'^$', ...) in my main app to private.MeLogin.as_view() in my core app?
EDIT:
I have tried the following,
def index(request):
return HttpResponseRedirect('/#/login')
but I get that this page has a redirect loop
The way to solve that be using a decorator, in this case login_required.
Django documentation
from django.contrib.auth.decorators import login_required
#login_required
def index(request):
index view code in here
What this will do is redirect you to your login view.
As mention in the Documentation
login_required() does the following:
If the user isn’t logged in, redirect to settings.LOGIN_URL, passing the current absolute path in the query string.
If the user is logged in, execute the view normally. The view code is free to assume the user is logged in.
You can also customize your decorator check the documentation for more information.
To login required, you must use a decorator indicating that:
from django.contrib.auth.decorators import login_required
#login_required
def index(request):
return render(request,'home.html')
In any view that the login is required, just use it.

Django: do not allow users to see pages when they are not logged in

I created a very basic login application. The LOGIN_URL, LOGIN_REDIRECT_URL and the LOGOUT_URL work just fine.
The thing is that if i log in succesully and then i close the window (browser) and then i reopen the browser, i can perfectly search the url (the one i am supose to only see if i am logged in) and use the applcation without loggin in again. This is not where it ends: if i open 2 separate browsers: Chrome and Firefox at the same time and i only logged in in ONE, i can use the applicaction from the other browser without problems.
I dont want this to happend. I tried using login_required in the urls.conf for the index view (the page that you can only see if you are logged in) and in the class view, i tried using stronhold, and django-braces. Is ther any other way to do this?. If you want to see any of the code let me know. Im using the login and log out that django implements (auth).
Than you
I know this is an old post but maybe the answer will help others in the future.
if you workflow is class based views you have to use: LoginRequiredMixin
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views import generic
class CreateGroup(LoginRequiredMixin, generic.CreateView):
fields = ('name', 'description')
model = Group
The LoginRequired mixin
When using class-based views, you can archive the same behavior as with login_required by using the LoginRequiredMixin. This mixin should be at the leftmost position in the inheritance list.
https://docs.djangoproject.com/en/2.0/topics/auth/default/
It would seem like you need to wrap the 'private' views with Django's login_required decorator:
from django.contrib.auth.decorators import login_required
#login_required
def my_view(request):
...
This will redirect to LOGIN_URL if the user is not logged in or authenticated.
in the view to the which your login redirects you can add:
def after_login(request,..):
if not request.user.is_authenticated():
redirect('some-non-existence-page-or-404',...)
#Your code
return

#login_required is losing the current specified language

I am using i18n_patterns to internationalize my app and it's working except when I click on a link that requires login (a view protected by #login_required decorator), I am being redirected to the login form in the default language instead of the currently active one.
How I can preserve the active URL? In other words, When in the French section, I want #login_required to redirect me /fr/login/?next=/fr/clients/ instead of /en/login/?next=/fr/clients/
I had the same issue, and I solved it by editing settings.py:
from django.core.urlresolvers import reverse_lazy
LOGIN_URL = reverse_lazy('login')
The function reverse_lazy adds the correct language prefix on the URL !
(with 'login' being the name of your login route)
I'm not well-versed in i18n for Django, but I don't think this is actually possible because login_required binds its login_url parameter to the decorated function at the point of decorator application. You're probably better off writing your own decorator; assuming you don't use either of the optional parameters to login_required, you can make your own as
from django.contrib.auth.views import redirect_to_login
from django.core.urlresolvers import reverse
import functools
def login_required(fn):
#functools.wraps(fn)
def _decorated(request, *args, **kwargs):
if request.user.is_authenticated():
return fn(request, *args, **kwargs)
path = request.get_full_path()
login_url = reverse('login')
return redirect_to_login(path, login_url)
where reverse('login') gets whatever the name of your login view in your urls.py is.
I haven't tested this, but if something comes up I'll try to debug it to the best of my ability.

Categories