disconnection does not happen - django

I want to set up the disconnection. I have a page, Page 1, that is only accessible to an authenticated user. When i disconnect I can still access page 1.
And i have anothers questions, How does Django know to execute the logout_user function ? (I have the same question for the login but as it works I didn't ask myself the question ^^).
And why do we indicate a redirection in the return when in the html we already indicate the redirection ?
appIdentification/views.py
from django.contrib.auth import authenticate, login, logout
def logout_user(request):
logout(request)
messages.success(request, ("You Were Logged Out!"))
return redirect('home')
appIdentification/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('/login', views.login_user, name="login"),
path('', views.logout_user, name="logout"),
]
mainApp/template/mainApp/page1.html
<body>
<h1> PAGE 1 </h1>
{% if user.is_authenticated %}
Logout
{% endif %}
</body>
mainApp/views.py
#login_required
def page1(request):
return render(request, 'mainApp/p1.html', {})
mainApp/urls.py
from django.urls import path, include
from . import views
path('mainApp', include('django.contrib.auth.urls')),
path('mainApp', include('appIdentification.urls')),
path('home', views.home, name="home"),
path('p1', views.page1, name="p1"),

Answer to your first problem
I have a page, Page 1, that is only accessible to an authenticated user. When i disconnect I can still access page 1.
because you've put wrong url for logout it shoud be
Logout
instead of
Logout
and for your second question
How does Django know to execute the logout_user function ?
Django use MVT pattern in this basically when you go to some url eg. /logout/ it calls view mapped to that url eg. logout_user() and if your view required any data from model then it gets from your model.
Answer to your last question
And why do we indicate a redirection in the return when in the html we already indicate the redirection ?
becouse it's a Post/Redirect/Get web development design pattern
When a web form is submitted to a server through an HTTP POST request, attempts to refresh the server response can cause the contents of the original POST to be resubmitted, possibly causing undesired results, such as a duplicate web purchase. Some browsers mitigate this risk by warning the user that they are about to re-issue a POST request.

Related

Two views same URL

I have a single dashboard_view URL path("", view=dashboard_view, name="dashboard").
On this page you can see the homepage unauthenticated. However, if you login, I present a modal popup to allow a user to populate a CreateForm.
The issue is that the dashboard_view doesn't have the form ( I have that in another view ). What is the best practice for this? Best for the user to have different options on the same page without having to switch pages.
You can use the login_required decorator. In login_required login_url is an optional parameter if you have declared the login path in the settings.py file. If your entire site has a login URL is the same. You can put LOGIN_URL = 'login_form_url' in the settings.py file.
from django.contrib.auth.decorators import login_required
#login_required(login_url='/login_form_url/')
def dashboard_view(request):
return render(request,'app_name/dashboard.html')

Django redirect from form upload

From the page
This page isn’t working. If the problem continues, contact the site owner.
HTTP ERROR 405
From the terminal
Method Not Allowed (POST): /
Method Not Allowed: /
[20/Dec/2021 22:00:27] "POST / HTTP/1.1" 405 0
How to redirect to the same page after page upload click.
form.html->included in sidebar.html-> included in home.html
<form method = "POST" action='.' enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Upload</button>
</form>
views.py
from django.shortcuts import render
from .forms import UserProfileForm
def index(request):
print(request.POST)
return render(request,'home.html')
urls.py
from django.conf import settings
from django.urls import path
from django.views.generic.base import TemplateView # new
urlpatterns = [
path('', TemplateView.as_view(template_name='home.html'), name='home'),
]
In your urls.py
Change to:
path(' ', index, name = 'home'),
And you also have to import your view in urls.py
Since you are redirecting to the same page, I assume you are also making a get request when you are serving the form on the webpage.
But when the page is served as a response to a GET request, it is not supposed to contain an empty dictionary in the POST attribute.
Thus, it provides an error.
According to me
def index(request):
if request.method == "POST" :
print(request.POST)
return render(request,'home.html')
Should solve the issue
Acc, to the Django documentation
It’s possible that a request can come in via POST with an empty POST dictionary – if, say, a form is requested via the POST HTTP method but does not include form data. Therefore, you shouldn’t use if request.POST to check for use of the POST method; instead, use if request.method == "POST"
For further reference - https://docs.djangoproject.com/en/3.2/ref/request-response/

How to set custom admin login URL in Django Admin on session timeout?

I wrote a Django app which has an external authentication system reacheable at some URL (say, https://.../myproject/login). This is working well.
However, when the session expires, the user gets redirected to the default login url which is https://.../myproject/admin). I'd like to change the behavior of the app so if the session expires, the user should be redirected to https://.../myproject/login and only use the /admin login when explicitly opened.
Is there a built-in way to do this in Django?
Django admin redirects the users to /admin/login when the session is expired or session is missing.
There are several ways to redirect users to https://.../myproject/login instead of https://.../myproject/admin/login.
Approach 1:
Override the view of myproject/admin/login URL with the view of myproject/login.
Let's say that myproject/login uses LoginView to render external system's login page, then add url(r'^admin/login/?$', LoginView.as_view(), name='admin:login') just above url(r'^admin/', include(admin.site.urls)) in myproject/myproject/urls.py
urlpatterns = [
url(r'^admin/login/?$', LoginView.as_view(), name='admin:login'),
url(r'^admin/', include(admin.site.urls)),
]
Pros:
Render the external system's login page instead of default Django admin login page on /myproject/admin/login
Cons:
The URL still points to myproject/admin/login
No way to access the default admin login page
Approach 2:
Override the view of myproject/admin/login url and redirect the user to myproject/login
Lets create a new view AdminLoginView then add url(r'^admin/login/?$', AdminLoginView.as_view(), name='admin:login') just above url(r'^admin/', include(admin.site.urls)) in myproject/myproject/urls.py
from django.core.urlresolvers import reverse
class AdminLoginView(TemplateView):
def get(self, request, *args, **kwargs):
"""
Assuming the name of the external system's login url is "login"
"""
return HttpResponseRedirect(reverse('login'))
urlpatterns = [
url(r'^admin/login/?$', AdminLoginView.as_view(), name='admin:login'),
url(r'^admin/default-login/?$', admin.site.login, name='default-admin-login'),
url(r'^admin/', include(admin.site.urls)),
]
Pros:
The URL changes to myproject/login
Cons:
You have to add extra code for the default login page.
I would recommend approach 2 to solve the problem mentioned in the question.
Thanks.
You can use LOGIN_URL and LOGOUT_REDIRECT_URL
https://docs.djangoproject.com/en/2.2/ref/settings/#login-url
Redirect to myproject/login for login (Default redirects to /accounts/login/)
LOGIN_URL = '/myproject/login/'
Redirect to the login page after log out (Default to None).
LOGOUT_REDIRECT_URL = '/myproject/login/'
IMO the best possible solution is to override the function for login view.
To do this add these lines of code in your urls.py containing the 'admin/'
# urls.py
def login(request):
if request.user and request.user.is_authenticated and request.user.is_active and request.user.is_staff:
return HttpResponseRedirect(reverse('admin:index', current_app='admin'))
else:
return HttpResponseRedirect(reverse('index', current_app='your_app_name'))
admin.site.login = login
# The lines below probably exist
# urlpatterns = [
# path('admin/', admin.site.urls),
# path('', include('your_app.urls')),
# ]

How to extend django.contrib.auth views?

How I've Arranged Templates : I have placed my login.html in /templates/registration folder of Django. So, the Django takes necessary care of accounts/login ,accounts/logout url requests and renders as per request. And I haven't to code for the individual login and logout functions.
What I am trying to Achieve : I want to authenticate users at login request, when they requests the login page:
If user is anonymous user, I want to render the normal login page.
However, If the user is authenticated thats already logged in. I want to display an error and not the logged page.
I want to achieve this in the views.py and urls.py and not in the templates by:
{% if user.is_authenticated %}
{% if user.is_anonymous %}
Urls.py
from django.conf.urls import url
from django.contrib.auth import views as auth_views
from . import views
urlpatterns=[
url(r'^register/$', views.register, name='register'),
url(r'^logout/$', auth_views.logout, {'next_page' : 'Homepage'}, name='logout'),
]
You can wrap the view with your own, which either redirects or calls the original.
def wrapped_login(request):
if request.user.is_authenticated:
return redirect('whatever')
else:
return auth_views.login(request)
Provide LOGIN_REDIRECT_URL = '/' in settings.py. Then use the following url for login page:
urlpatterns = [
url(r'^login/',
auth_views.LoginView.as_view(redirect_authenticated_user=True),
name='login'),
]
This will redirect your user to the URL provided in settings file if they try to login even after being authenticated.

Does using Django "is_superuser" require additional URL?

I'm creating an administrative interface/dashboard for a Django 1.7 project. Instead of creating a new admin application from scratch, I'm trying to use Django's built-in admin site. I have "root" (superuser) and "reviewer" (non-superuser) staff accounts. Both accounts are in the default "admin" group. Both accounts can log in to the admin site but some pages are accessible by both the root and reviewer accounts while access to others is limited to the superuser. I've created the two following views:
# mysite/apps/admin/views.py
from django.shortcuts import render
from django.contrib.auth.decorators import user_passes_test
#user_passes_test(lambda u: u.is_staff)
def all_admins(request, template):
return render(request, template)
#user_passes_test(lambda u: u.is_superuser)
def superuser_only(request, template):
return render(request, template)
The problem I'm running into is that if I log is using the reviewer account and click the anchor for the "superuser_only" page, I get the following error:
Page not found (404)
Request Method: GET
Request URL: http://localhost:8001/accounts/login/?next=/admin/super/
Using the URLconf defined in conf.urls, Django tried these URL patterns, in this order:
^admin/
^admin/all_admins/$ [name='all-admins']
^admin/super/$ [name='superuser-only']
The current URL, accounts/login/, didn't match any of these.
Is there something else I need to do to implement this superuser-only view and template so that this error doesn't occur if the reviewer clicks the link?
I followed the Django docs instructions and created my own copies of Django's base.html, base_site.html, and index.html templates in my mysite/apps/admin/templates/admin directory and then added the "all_admins" and "superuser_only" anchors to the bottom of the index.html page.
Here are my files:
# part of mysite/mysite/settings.py
TEMPLATE_DIRS = (
os.path.join(BASE_DIR, 'apps/admin/templates'),
os.path.join(BASE_DIR, 'apps/admin/templates/admin'),)
# mysite/mysite/urls.py
from django.conf.urls import patterns, include, url
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
url(r'^admin/', include(admin.site.urls)),
url(r'^admin/all_admins/$',
'apps.admin.views.all_admins',
{'template': 'all_admins.html'},
name='all-admins'),
url(r'^admin/super/$',
'apps.admin.views.superuser_only',
{'template': 'superuser_only.html'},
name='superuser-only'),
)
Then user doesn't pass the test django redirects it to the login page. Defult url for this page is /accounts/login/. Set the LOGIN_URL setting to the admin's login page:
LOGIN_URL = 'admin:login'
Or, if you have non-staff users on the site, set the auth urls in the urls.py:
url('^accounts/', include('django.contrib.auth.urls')),
But this will require you to create several templates (login, logout, change password etc.)
UPDATE: If you want to show a message in the login page then you can create the custom login template for admin. Add this line to your urls.py:
admin.site.login_template = 'my_login.html'
And then create my_login.html template which is extended from admin/login.html:
{% extends 'admin/login.html' %}
{% block content %}
{% if user.is_staff %}
<p class="errornote">You need to be a superuser to access that page.</p>
{% endif %}
{{ block.super }}
{% endblock %}
UPDATE 2: If you don't want to change site-wide LOGIN_URL or implement auth by including django.contrib.auth.urls in your urls.py then you can pass login_url parameter to the #user_passes_test decorator:
#user_passes_test(lambda u: u.is_superuser, login_url='/admin/login/')
def superuser_only(request, template):
return render(request, template)