I am working on a project where an organization will login and then logout if they want. But somehow the logout functionality is not working. No redirect is happening and the user is not able to logout.
# urls.py
urlpatterns = [
path('logout',views.user_logout,name = 'logout')
]
# views.py
def user_logout(request):
if request.method == "POST":
logout(request)
return HttpResponseRedirect('login')
# template:
<a href="#" onClick="document.getElementById('logoutform').submit()" class="btn">
Logout</a>
<form id="logoutform" method="POST" action="{% url 'logout' %}">
{% csrf_token %}
<input type="hidden">
</form>
The page just reloads and no redirect happens.
I think you've made this more complicated than it needs to be. Django comes with a LogoutView, and it allows logouts with GET requests. You could use that logout view, or change your own to:
from django.shortcuts import redirect
def user_logout(request):
logout(request)
return HttpResponseRedirect('login') # assumes you have a URL pattern with name='login'.
Note that HttpResponseRedirect('login') will redirect to the relative URL 'login', so you might end up at /logout/login. You should either use the absolute URL (e.g. HttpResponseRedirect('/login/')), reverse the URL (e.g. return HttpResponseRedirect(reverse('login')), or use the redirect shortcut which takes care of reversing for you.
Once you have changed the logout view, you can remove the form and simply link to the logout page.
Logout
Related
I'm trying to create a usercreationform on the homepage of my website. After reading and watching tutorials on user creation I noticed everyone creates a separate HTML page for "signup", however, I want my signup page to be directly on my homepage - is this a possibility? I'm finding it difficult to understand with 'accounts' having its own separate app, as well as the homepage having its own app, which I have called mine 'game'. Do both apps have to be separate? Am I able to make the accounts app my main 'homepage' app?
Can anyone recommend any tutorials on this? I think I should also mention I'm quite new to django. Thank you.
My homepage app (titled game)
urls.py:
from django.contrib import admin
from django.urls import path
from.import views
urlpatterns = [
path('', views.game_start),
]
views.py:
from django.shortcuts import render
from django.contrib.auth.forms import UserCreationForm
from .models import Game
def game_start(request):
games = Game.objects.all().order_by('date') # grabs all records in game in db table, order by date
return render (request, 'game/game_start.html', {'games':games})
def signup_view(request):
form = UserCreationForm()
return render(request, 'game/game_start.html', {'form': form})
accounts/urls.py:
from django.conf.urls import url
from .import views
app_name = 'accounts'
urlpatterns = [
path('', game_views.game_start, name="home"),
]
accounts/views.py:
from django.http import HttpResponse
from django.shortcuts import render
def about(request):
# return HttpResponse('Price is right game one')
return render(request, 'about.html')
I want my signup page to be directly on my homepage - is this a possibility?
Yes it's a possibility that you can define a custom signup function in your accounts app and then import that inside of your homepage app like this:
accounts/views.py:
def signup(request):
data = {'form':None, 'user_created': False}
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
user = form.save()
# do soemthing with the registered user
data['user_created'] = True
else:
form = UserCreationForm()
data['form'] = form
return data
homepage/views.py:
from accounts.views import signup
def game_start(request):
games = Game.objects.all().order_by('date')
data = {'msg': ''}
response = signup(request)
if response['user_created']:
# you can redirect user here to somewhere else when they have been registered.
data['msg'] = 'Thanks for being the part of our beautiful community!'
return render(request, 'game/game_start.html', {
'games':games,
'form': response['form'],
'msg': data['msg']
})
game_start.html:
<p>{{msg}}</p>
<form action="/" method="post">
{% csrf_token %}
{{ form }}
<button type="submit">Sign Up</button>
</form>
Do both apps have to be separate?
Well, you can have both of them under one app but that is not recommended because of the following reasons:
You won't take advantage of App Reusability.
All of your code would look messy.
Debugging would be hard.
If you are having difficult understanding what apps in django are, then you can simply take a look at my answer here
You could include the form in your "game_start.html" template:
{% if not user.is_authenticated %}
<form role="form"
action="{% url 'player_login' %}"
method="post">
{% csrf_token %}
<p>Please login.</p>
{{ form.as_p }}
<button type="submit">Sign in</button>
</form>
{% endif %}
This assumes you have a named url pattern player_login.
I have made a simple form inside a html file whose path is www.site.com/posts/5. Whenever the form is submitted, it redirects back to the same page i.e www.site.com/posts/5 displaying a message given by user in the form.
However, whenever the form is submitted it doesn't call the foobar view.
The urls.py, views.py and html files are as follows:-
urls.py
urlpatterns = [
path('posts/<int:foo>',user_views.display, name="display",
path('posts/<int:foo>',user_views.foobar, name="makefoo"),
]
views.py
def foobar(request, foo):
#do something
html file
<form name="fooform" action= "{% url 'makefoo' 5 %}" method = "post">
{% csrf_token %}
<input type="text" name="FOO_BODY" maxlength="300" required>
<input type="submit" value="comment">
<input type="reset" value="clear">
</form>
Edit : user_views is just from user import views as user_views
You can not attach two views to the same URL. The {% url ... %} template tag, only generates a URL for that path. But if there is a "url clash", then it is possible that the requests ends up in the other view.
You thus should define another URL, or encode the post logic in the display view. In case of a POST request, you can thus first take the necessary steps, and then for example return a redirect to the page, such that we can again render the page:
def display(request, foo):
if request.method == 'POST':
# do something
return redirect(display, foo=foo)
#do something else (original code)
return HttpResponse(..)
This is the famous Post/Redirect/Get web development design pattern [wiki]. This is usually better than returning a HTTP response directly in the POST, since if the user performs a refresh, the POST will be performed a second time.
As mentioned in the comment by #williem, you have two path() defined in the urls.py.
Always First matching route will be picked up from the url route table. So whenever r^'posts/' is requested it will call the display() from the user_views, so it will never go to foobar(). Either remove the route with display() or change the sequence. Also, I assume you imported the user_views.
Reference:
https://docs.djangoproject.com/en/2.1/topics/http/urls/
I have created a login view in my project urls.py,
urlpatterns = [
path('login/', views.LoginView.as_view(template_name='login.html'), name='login'),
]
login.html
<div class="container">
<h2>Login</h2>
<form action="\" method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Login</button>
</form>
</div>
Till here it works fine I can see login page and login into it. But now I can login with any anonymous credentials and they can see the home page.
So how do I restrict it to registered user and then logout them.
When you add path('login/'... stuff to urls.py it does nothign to access to home page. You will need to either forbid access to homepage explicitly by adding login_required to your view:
from django.contrib.auth.decorators import login_required
#login_required
def my_view(request):
...
Or you can use LoginRequiredMixin for class based view. Or as another option you can use django-stronghold package.
I have been trying to set up a test version of a captcha form using the Django CMS, Mezzanine. It displays the captcha, but when I submit the form I get the error:
Forbidden (403)
CSRF verification failed. Request aborted.
Help
Reason given for failure:
CSRF token missing or incorrect.
In general, this can occur when there is a genuine Cross Site Request Forgery, or when Django's CSRF mechanism has not been used correctly. For POST forms, you need to ensure:
Your browser is accepting cookies.
The view function uses RequestContext for the template, instead of Context.
In the template, there is a {% csrf_token %} template tag inside each POST form that targets an internal URL.
If you are not using CsrfViewMiddleware, then you must use csrf_protect on any views that use the csrf_token template tag, as well as those that accept the POST data.
You're seeing the help section of this page because you have DEBUG = True in your Django settings file. Change that to False, and only the initial error message will be displayed.
You can customize this page using the CSRF_FAILURE_VIEW setting.
The behavior is the same with Firefox and Chrome (with or without incognito). I am using Python 3.4, Django 1.6.7, and Mezzanine 3.1.0. I have tried to fix the problem in several ways:
1) My html template:
<body>
<h3>Captcha</h3>
<form method="POST">
{% csrf_token %}
<input name="item_text" id="id_new_item" placeholder="Enter item">
<br>
{{ form.captcha }}
<input type="submit" value="Submit">
</form>
</body>
2) In my settings.py file:
TEMPLATE_CONTEXT_PROCESSORS = (
...
"django.core.context_processors.csrf",
)
MIDDLEWARE_CLASSES = (
...
"django.middleware.csrf.CsrfViewMiddleware",
)
3) In my captcha_test.views.py:
from django.views.decorators.csrf import csrf_protect
from django.shortcuts import render_to_response
from django.http import HttpResponse
from captcha_test.forms import CaptchaTestForm
#csrf_protect
def captcha_page(request):
if request.POST:
form = CaptchaTestForm(request.post)
if form.is_valid():
human = True
return HttpResponseRedirect('/')
else:
form = CaptchaTestForm()
return render_to_response('captcha.html', locals())
My forms.py file, if this helps at all:
from django import forms
from captcha.fields import CaptchaField
class CaptchaTestForm(forms.Form):
item_text = forms.CharField()
captcha = CaptchaField()
Any insights? Thanks for your help!
You must ensure that:
The view function uses RequestContext for the template, instead of Context.
But you use:
return render_to_response('captcha.html', locals())
And, from the documentation to render_to_response:
By default, the template will be rendered with a Context instance (filled with values from dictionary). If you need to use context processors, render the template with a RequestContext instance instead.
So adding context_instance=RequestContext(request) should solve the problem.
When I try to go to URL of view with #login_required, it redirects me to login form. But the rendered form has no action=attribute and when I click submit button nothing happens. But when I go to /admin/ I got the working login form. After I log in that way all views are working. I'm using admin_bootstrap so it's different login form. But why the default one is acting that way?
Relevant code:
mySubApp/views.py:
#login_required
def index(request):
user = request.user
return HttpResponse("Hello, world. You're at index.")
mainApp/urls.py:
#login
url(r'^login/$', 'django.contrib.auth.views.login', name='LogMeIn'),
#mySubApp
url(r'^subapp/', include('mySubApp.urls')),
mySubApp/urls.py:
urlpatterns = patterns('',
url(r'^$', views.index, name='index'),
)
settings.py:
LOGIN_URL = 'LogMeIn'
Do I need to create a custom login form to make it work or what?
You have to define your own templates when using the authentication views (they aren't provided by defualt):
Django provides several views that you can use for handling login, logout, and password management. These make use of the stock auth forms but you can pass in your own forms as well.
Django provides no default template for the authentication views - however the template context is documented for each view below.
So create a registration/login.html:
<form action="{% url auth:login %}" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>