I'm following a tutorial to build a To Do list in Python and Django, I've finished implementing authentication and User-based access using built-in views,
Upon clicking the "logout" button I'm correctly redirected to the login page. However, if I type http://localhost:8000/logout directly in the URL it shows a 405 error. My goal is to redirect the user if someone directly types the URL to the login page. How do I do that?
Below is my url.py
file
from django.urls import path, reverse_lazy
#from . import views # For Functions, thus but now it's class so
from .views import TaskList, TaskDetail, TaskCreate, TaskUpdate, TaskDelete, CustomLoginView, RegisterPage # CLASSES FROM VIEWS FILES
from django.contrib.auth.views import LogoutView
urlpatterns = [
path('login/',CustomLoginView.as_view(),name='login'),
path('logout/',LogoutView.as_view(next_page=reverse_lazy('login')),name='logout'),
path('register/', RegisterPage.as_view(),name="register"),
path('', TaskList.as_view(), name='tasks'), # root URL - #base url thus empty string, view name
path('task/<int:pk>', TaskDetail.as_view(), name='task'), # when clicked on list item - sub url <int:pk> - pk - primary key
path('create-task/', TaskCreate.as_view(), name='task-create'), # url accessed to create the task
path('update-task/<int:pk>', TaskUpdate.as_view(), name='task-update'), # url accessed to update the task
path('delete-task/<int:pk>', TaskDelete.as_view(), name='task-delete'), # url accessed to delete the task
]
Below are my relevent view.py functions
from django.shortcuts import render, redirect
from django.http import HttpResponse
from django.views.generic.list import ListView
from django.views.generic.detail import DetailView #description pane
from django.views.generic.edit import CreateView, UpdateView, DeleteView, FormView # create form; update prefill and modify the data
from django.urls import reverse_lazy # redirects user to certain part or page
from django.contrib.auth.views import LoginView
from django.contrib.auth.mixins import LoginRequiredMixin #add this before builtin view to prevent unauthorised user accessing data,
from django.contrib.auth.forms import UserCreationForm #built in user creation
from django.contrib.auth import login #to login user automatically once registered
from .models import Task
# Create your views here.
#if not logged in then restrict people from seeing it
#gatekeeper thus on top - login optionality
class CustomLoginView(LoginView):
template_name = 'base/login.html'
fields = '__all__'
redirect_authenticated_user = True #--- unauthenticated users to be redirected
def get_success_url(self):
return reverse_lazy('tasks')
class RegisterPage(FormView):
template_name = 'base/register.html'
form_class = UserCreationForm #--- passing prebuilt form
redirect_authenticated_user = True
success_url = reverse_lazy('tasks') #--- redirect on success when registered
def form_valid(self, form): #-- the form submission is valid by rules
user = form.save() #-- save the user
if user is not None: #-- is user is suceesfully created
login(self.request, user) #-- redirect control to login function for autologin
return super().form_valid(form)
def get(self,*args, **kwargs):
if self.request.user.is_authenticated:
return redirect('tasks')
return super().get(*args,**kwargs)
Below is where the logout button is placed in the whole application
task_list.html
<!-- homepage tasks listing -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>To Do</title>
</head>
<body>
{% if request.user.is_authenticated %}
<p>{{ request.user }}</p>
<!-- <a href="{% url 'logout' %}">Log Out</a> Won't work error 405, need POst and csrf token by django -->
<form action="{% url 'logout' %}" method="post">
{% csrf_token %}
<button type="submit">Logout</button>
</form>
{% else %}
<a href="{% url 'login' %}">Log In</a>
{% endif %}
<hr>
<h1>My To Do List</h1>
<a href="{% url 'task-create' %}"> Add Items</a>
<table>
<tr>
<th>Items</th> <!-- th acts as cell header -->
<th> </th> <!-- #td only shows if we've a th for each td-->
<th> </th>
<th> </th>
</tr>
<!-- loop through all the items -->
{% for task in tasks %} <!-- this si django templating syntax-->
<tr>
<td>{{task.title}}</td> <!-- td acts as cell value -->
<td><a href="{% url 'task' task.id %}">View</a></td>
<td><a href="{% url 'task-update' task.id %}">Edit</a></td>
<td><a href="{% url 'task-delete' task.id %}">Delete</a></td>
</tr>
{% empty %}
<h3>No Items in List</h3>
{% endfor %}
</table>
</body>
</html>
I've tried searching but everywhere only the below solution is mentioned and only for a dedicated button. no solution on how to handle the localhot:8000/logout URL
<form action="{% url 'logout' %}" method="post">
{% csrf_token %}
<button type="submit">Logout</button>
</form>
based on the Django
's source code for LogoutView
class LogoutView(RedirectURLMixin, TemplateView):
"""
Log out the user and display the 'You are logged out' message.
"""
http_method_names = ["post", "options"]
template_name = "registration/logged_out.html"
extra_context = None
@method_decorator(csrf_protect)
@method_decorator(never_cache)
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
"""Logout may be done via POST."""
auth_logout(request)
redirect_to = self.get_success_url()
if redirect_to != request.get_full_path():
# Redirect to target page once the session has been cleared.
return HttpResponseRedirect(redirect_to)
return super().get(request, *args, **kwargs)
linked here: https://github.com/django/django/blob/main/django/contrib/auth/views.py
This view will not handle GET
requests and when you call it, will return 405 Method Not Allowed
.
So if you really need to do this, you have to write your own Logout
view.