Pass request.session after function is executed - django

I have app, with authentication and when user logs out, I want a notification message to be displayed. My logout view looks like:
def logout_view(request):
logout(request)
message = 'Logout successfull'
request.session['message'] = message
return redirect('index')
And my index(the one i'm redirecting to) view looks like:
def index(request):
context = {}
if request.session:
message = request.session['message']
context['message'] = message
return render(request, 'index.html', context)
My index.html:
{{ message }}
Now logged in or out when i go to my index view I see message. When I click on button which logs me out I still see message. I want users only to be able to see messages if they logged out.
I don't know if this is possible and if it isn't then you may tell me another way to pass context with redirect function.
Thanks for help!

Clear the message after you've shown it to the user.
Check if message is in the session, if so, a message needs to be displayed.
You're getting a KeyError because you're not checking if message is inside request.session before accessing it.
def index(request):
context = {}
if request.session and 'message' in request.session:
context['message'] = request.session['message']
del request.session['message']
return render(request, 'index.html', context)

Related

flask login_required next parameter not working

i followed miguel grinberg tutorial and now i'm applying what i learned in a side project but in all cases i came a cross some problem which i ignored at first and thought it is my mistake but after investigation i can't find why this behavioud happens, the problem is when i try to go to any url within the website while not logged on log-in screen comes but after that the original requested page is not loaded successfully and flask throughs BuildError exception.
below is my code samples
#app.route('/login', methods=['GET', 'POST'])
def login():
if current_user.is_authenticated:
return redirect(url_for('index'))
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(username= form.username.data).first()
if user is None or not user.check_password(form.password.data):
return redirect(url_for('login'))
login_user(user)
next_page = request.args.get('next')
if not next_page or url_parse(next_page).netloc != '':
return redirect(url_for('index'))
return redirect(url_for(next_page))
return render_template('login.html', form=form)
as you can see i'm getting next parameter and doing some security checks if it exists then redirecting to next_page url , but what happens is that there is build error, for exmpale something like the following
BuildError: Could not build url for endpoint u'/user/4556'. Did you mean
'user' instead?
while user view function looks like this
#app.route('/user/<username>', methods=['GET'])
#login_required
def user(username):
....
Instead of
return redirect(url_for(next_page))
you probably want
return redirect(next_page)
Your "next" parameter would look like "/user/4556" but you don't have an endpoint called "/user/4556", so you don't want to pass that to url_for. Passing the string directly to redirect will suffice.

Django Cookie with Login function

I'm trying to set my first cookie with Django when users are logged on my application.
When user is logged, the template is well-displayed but none cookie in my application which is named : Cookie
My function looks like :
def Login(request):
error = False
if request.method == "POST":
form = ConnexionForm(request.POST)
if form.is_valid():
username = form.cleaned_data["username"]
password = form.cleaned_data["password"]
user = authenticate(username=username, password=password)
if user:
login(request, user)
toto = GEDCookie(request)
return render(request, 'Home_Homepage.html', {'toto':toto})
else:
error = True
else:
form = ConnexionForm()
return render(request, 'Authentication_Homepage.html', locals())
#csrf_exempt
def GEDCookie(request):
SID = Logger.login("test", "10test")
response = HttpResponse("Cookie")
response.set_cookie('Cookie', SID, max_age=None)
return response
I missed something in my script ?
This isn't how you use cookies at all.
Inside your Login view, you're calling a separate view - GEDCookie that returns an HTTP response. But instead of returning that response directly to the user, which would set the cookie, you're for some reason trying to insert it in a template. That doesn't make sense.
If you want to set a cookie in your login view, you need to do so on the response that you return to the user.
Note also that after a successful login (or other post), you should always redirect, not display a template directly. So:
if user:
login(request, user)
response = redirect('home')
response.set_cookie('whatever')
return response
Finally, you almost certainly don't need a cookie here in any case. If you want to store data related to the current user, use the session.
As you can clearly see that you are not attaching your cookie to your real response, you are passing it as the context in render function which is an issue.
def Login(request):
error = False
if request.method == "POST":
form = ConnexionForm(request.POST)
if form.is_valid():
username = form.cleaned_data["username"]
password = form.cleaned_data["password"]
user = authenticate(username=username, password=password)
if user:
login(request, user)
SID = Logger.login("test", "10test")
response = render(request, 'Home_Homepage.html', {})
response.set_cookie('Cookie', SID, max_age=None)
return response
else:
error = True
else:
form = ConnexionForm()
return render(request, 'Authentication_Homepage.html', locals())
https://docs.djangoproject.com/en/3.0/ref/request-response/#django.http.HttpResponse.set_cookie Please refer this link for individual arguments of inbuilt function.
Create signal.py in app. where your user model is present or add in main project directory and Add below snippet in signal.py
from django.db.models.signals import pre_save, pre_delete, post_save, post_delete
from django.dispatch import receiver
from django.dispatch import Signal
from allauth.account.signals import user_logged_in # it signal for post login
from django.shortcuts import render
#receiver(user_logged_in) # Decorator of receiving signal while user going to logged in
def post_login(sender, user, request, response, **kwargs):
response.set_cookie('team', 'india') # This will set cookie
return response
In given snippet, default response will come in argument, so direct redirect to that response, if you want to change then render other template using render/redirect django.shortcuts methods like below,
response = render(request, 'base.html', {})

Redirect user to Django 500 error page from function instead of view?

I have a Django view that looks for a variable in the user's session and, if it can't find it, raises a 500 error and redirects the user to my custom 'project/templates/500.html' page.
# views.py
def process_country(request, template):
try:
country = request.session['country']
except KeyError as e:
msg = "Key %s not found for uid %s" % ('country', request.user.id)
log.error(msg, exc_info=True)
return render(request, '500.html', status=500)
if request.method == "POST":
# do stuff...
pass
else:
form = MyForm(initial={'country': country})
context = {'form': form}
return render(request, template, context)
This view works as intended if the 'country' session variable doesn't exist. However, what I'd like to do is move this ugly block of exception handling code to a helper function:
# views.py
from utils import get_from_session
def process_country(request, template):
country = get_from_session(request, 'country') # Helper
if request.method == "POST":
# do stuff...
pass
else:
form = MyForm(initial={'country': country})
context = {'form': form}
return render(request, template, context)
# utils.py
from django.shortcuts import render
def get_from_session(request, key):
try:
value = request.session[key]
return value
except KeyError as e:
msg = "Key %s not found for uid %s" % (key, request.user.id)
log.error(msg, exc_info=True)
# Neither of these work!
#return render(request, '500.html', status=500)
#render(request, '500.html')
The problem is that in this second version, the user doesn't get redirected to the custom 500.html error page. Instead, Django displays the template passed to the process_country view but it embeds the raw HTML contained in the 500.html page in that template. I guess I could do an HttpResponseRedirect(reverse('500-page')) but that would entail creating a view and it doesn't feel like the right solution. What's going on here? Can I redirect the user to the custom 500.html template from a function and if so, how?
Thanks.
Raise an error this display 500.html in production automaticaly
raise KeyError
But this wrong way, you should never raise exceptions for user. Instead this you may checks country in your view and if it's not exists, for example, display some message for user in template.

django: refresh with an invalid form

The problem is when refreshing the page with an invalid form (with errors displayed on the page) I get "Confirm Form Resubmission" alert and hitting 'ok' I end up with the same invalid form with errors. This behavior seems a bit strange to me, I suppose I should get an empty form.
In case the form is submitted (by pressing the submit button) I get a POST request and process that POST request in my view function. I do check my form's validity. In case it is valid I HttpResponseRedirect to the success page, in case not, I respond with that invalid form (in order to not loose the users data and have errors displayed on the page). This is the expected behavior of the view function (at least to me).
BUT the problem is that the refresh also "triggers" POST request. This is strange, if someone could explain why refresh triggers that alert and sends a POST request, I'd be many thankful. I'm new to web and eager to understand what is going under the hood.
So, as in my view function I get the same POST than I have to go the same way as well as with the "submit button" case, right? I can't "distinguish" whether it was a submit or a refresh? I've dumped the request dict for both cases, those are identical.
What I'm missing here? I've done lot of search for this but couldn't get any answers. In almost every case I end up with a case of valid form with suggestion to use HttpResponseRedirect, all right, but what if the form is invalid? User has entered some invalid data then he/she decides to start with a new empty form. The only way now is to click on the url and hit enter. Shall he/she be able to do this with refresh?
Lot of thanks for your answers.
Regards,
Karen
P.S. Here is the code:
class TireFormView(FormView):
template_name = 'tire_form.html'
form_class = TireForm
success_url = '/tires/tire/thanks'
initial = {'make': MAKE_CHOICES[0][1]}
def get(self, request, *args, **kwargs):
form = self.form_class(request=request, initial=self.initial)
return render(request, self.template_name, {'form': form})
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST, request = request)
if form.is_valid():
return HttpResponseRedirect(self.success_url)
return render(request, self.template_name, {'form': form})
HTML
...<form action="">...

Automatic HTTPRedirect in Django view if user is authenticated?

I have successfully made it so the user must log in to view their profile, however, I only want the user to be able to view their profile and no one else.
Previously, they could visitwww.websitename.com/user/admin
as well as www.websitename.com/user/test and it would bring up the data for the profile each time of the logged in user.
The URL to visit is www.websitename.com/user/usernameofcurrentuser
Profile Page View
def profile_page(request, username):
context = RequestContext(request)
if request.user == username:
if request.user.is_authenticated():
user = User.objects.get(username=username)
taskitems = request.user.taskitem_set.all()
return render_to_response('profile.html', {}, context)
else:
return render_to_response('login.html', {}, context)
else:
return render_to_response('login.html', {}, context)
However, even though the user is logged in, it's redirecting them to the sign in page. I know the user is logged in because it prints their name on the login page, yet it's not redirecting them to the profile associated with the username.
You can try this :
def profile_page(request, username):
if request.user.is_authenticated():
if request.user.username == username:
# removed user since already in request.user and available in template as 'user'
# removed taskitems since directly available in template as 'user.taskitem_set.all'
return render(request, 'profile.html')
else:
return HttpResponseRedirect(reverse('profile_page', args=(request.user.username,)))
else:
return render(request, 'login.html')
Remove the username parameter since each user should only view their own profile. You can also use the login_required decorator to remove the extra conditional:
from django.contrib.auth.decorators import login_required
from django.shortcuts import render
#login_required
def profile_page(request):
return render(request, 'profile.html')
Make sure to set LOGIN_URL in your settings.py so unauthenticated users get redirected to the right spot.