Django authentication system - python

i'm using the django built in authentication system and in my login template i have this code :
login.html:
{% block title %}Login{% endblock %}
{% block content %}
<h2>Login</h2>
{% if user.is_authenticated%}
you are already logged in
{% else %}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Login</button>
</form>
{% endif %}
{% endblock %}
but what i really want to do is to redirect the user to the home page if he tries to access login page while already logged in, but i am new to django so i don't know how to do that.

For django>=1.11 you can set redirect_authenticated_user parameter to True in its url in url_patterns to do the redirect, like this:
from django.contrib.auth import views as auth_views
urlpatterns = [
url(r'^login/', auth_views.LoginView.as_view(redirect_authenticated_user=True), name='login'),
]
read the document for more information.
and also set LOGIN_REDIRECT_URL in your setting file to your index url or its name:
LOGIN_REDIRECT_URL = '/index/'

In your `settings.py' add this:
LOGIN_REDIRECT_URL = 'index'
if the url name of your index is 'index', else put the correct url name

You can do it in your views.py file.
def login(request):
if request.method =="get":
if request.user.is_authenticated:
return render(// youre code)

Related

Django How to pass username in a predefined template

I created a templates for header/footer and imports, if I want to acess the username in my header template I cant do that because it has no views. How can I pass the username to the header template?
header_template.py
from django import template
register = template.Library()
#register.inclusion_tag('home/partials/header.html')
def header(element):
return {'element': element, }
Import in Template
{% load header_template %}
{% header context %}
Usage in the template:
{% if user.is_authenticated %}
<a class="btn btn-primary display-4" href="{% url 'home:profil' %}">Profil</a>
{% else %}
<a class="btn btn-primary display-4" href="{% url 'home:login' %}">Login</a>
{% endif %}
Thanks for your help.
You can take context in your tag:
#register.inclusion_tag('home/partials/header.html', takes_context=True)
def header(context, element):
return context | {'element': element}
Read more here:
https://docs.djangoproject.com/en/dev/howto/custom-template-tags/#inclusion-tags
My opinion, you are don't need this, The cause for every new tag in template - a wrong logic.

Django - i always get my profile when i what to view another users profile

Whenever i tried to view other people profile, it always return my own profile again, i don't really know what's wrong and i have tried calling request.user but it seems not to work
views.py
def UserProfile(request, username):
user = get_object_or_404(User, username=username)
profile = Profile.objects.get(user=user)
url_name = resolve(request.path).url_name
context = {
'profile':profile,
'url_name':url_name,
}
return render(request, 'userauths/profile.html', context)
urls.py main project
from userauths.views import UserProfile
urlpatterns = [
path('admin/', admin.site.urls),
path('users/', include('userauths.urls')),
path('<username>/', UserProfile, name='profile'),
]
index.html
{% for creator in creators %}
<img class="avatar-img rounded-circle" src="{{creator.user.profile.image.url}}" alt="creators image" ></div>
<h5 class="card-title"><a href="{% url 'profile' creator.user %}">
{{creator.user.profile.first_name}} {{creator.user.profile.last_name}} {% if creator.verified %} <i class="bi bi-patch-check-fill text-info smsall" ></i> {% else %}{% endif %} </a></h5>
<p class="mb-2">{{creator.user.profile.bio}}</p></div>
{% endfor %}
I just fixed it now, in my profile.html, i am using {{request.user.profile.first_name}} to display the informations. I was supposed to use {{profile.first_name}} etc, and that was it.
Instead of this:
<a href="{% url 'profile' creator.user %}">
you should try:
<a href="{% url 'profile' creator.user.username %}">
From the presumably working statement get_object_or_404(User, username=username) I assume that username is a field (hopefully, unique) of the User. So you should pass it onto the URL, not the entire User model.

Pass additional context variable data into allauth views using class based views

Not sure how to pass additional context data into various allauth forms which includes my own templates. For my own views I'm using get_context_data() which is working fine. I'm including small templates into a master template such as a header, footer, side bar etc. Everything is working except when allauth kicks in such as login, logout, email confirmation window etc my context variables are not passed so images in my left side bar are not showing up but allauth works fine.
I've tried a few things but I believe the ideal option is to inherit from allauth views for that function such as login, password reset, confirm email etc, supply my own context variable data.
In my accounts.views.py, I'm expecting this to fail as the template doesn't exist but the form still shows up and the UserProfile image isn't being shown in the left side bar.
from allauth.account.views import ConfirmEmailView
class EmailViewExt(ConfirmEmailView):
template_name = "account/signup_alternate1.html"
def get_context_data(self, **kwargs):
context = super(ConfirmEmailView).get_context_data(**kwargs)
context['userprofile'] = UserProfile.objects.get(user=self.request.user)
return context
In my template left_bar_base.html which is included from my overridden allauth template.
{% if userprofile.avatar_picture %}
<img src="{{ userprofile.avatar_picture.url }}" class="card-img-top" alt="...">
{% else %}
<img src="{% static 'placeholder.png' %}" class="card-img-top" alt="...">
{% endif %}
In my email_confirmation.html I have this at the top.
{% extends "ui/base.html" %}
{% load i18n %}
{% load account %}
{% block header %}
{% include "ui/loggedin_header.html" %}
{% endblock %}
{% block left %}
<div class="row no-gutters justify-content-start">
{% include 'ui/left_bar_base.html' %}
{% endblock %}
{% block content %}
... allauth template code...
Came across the solution.
My EmailViewExt(ConfirmEmailView) was never being called.
So instead of using allauths.urls I put this right above the allauths.urls.
urlpatterns = [
path('admin/', admin.site.urls),
path('accounts/email/', EmailViewCustom.as_view(), name="email"),
path('accounts/', include('allauth.urls')),
Now the context variable I've added is being passed into my templates. So I guess I have to add all of the urls from allauth for the ones I want to replace.

Django - template not being detected

I'm using this library to handle two factor auth for a django project, but i'm having some troubles: in my site, i added a setup.html page, i set the url on my urls.py file but i keep getting this error:
In template C:\Users\Us\lib\site-packages\allauth\templates\base.html, error at line 26
Reverse for 'account_email' not found. 'account_email' is not a valid view function or pattern name.
<li>Change E-mail</li>
Which is completely weird because i'm not trying to load a file called base.html but my own setup.html file, which is located in my project's folder (the path is project-folder>templates>setup.html). This is the setup.html that i would like to load from my own templates:
{% extends 'main/header.html' %}
{% load i18n %}
{% block content %}
<h1>
{% trans "Setup Two-Factor Authentication" %}
</h1>
<h4>
{% trans 'Step 1' %}:
</h4>
<p>
{% trans 'Scan the QR code below with a token generator of your choice (for instance Google Authenticator).' %}
</p>
<img src="{{ qr_code_url }}" />
<h4>
{% trans 'Step 2' %}:
</h4>
<p>
{% trans 'Input a token generated by the app:' %}
</p>
<form method="post">
{% csrf_token %}
{{ form.non_field_errors }}
{{ form.token.label }}: {{ form.token }}
<button type="submit">
{% trans 'Verify' %}
</button>
</form>
{% endblock %}
It looks like the module that i'm using, instead of loading MY setup.html will load something else, but i can't find a way to fix this.
Here is the view that i'm calling to handle the setup (it' the module's view):
https://github.com/percipient/django-allauth-2fa/blob/master/allauth_2fa/views.py
And here is my own urls.py, where the view that i mentioned is being called:
from django.urls import path
from . import views
from django.conf.urls import url, include
from django.conf.urls import url
from allauth_2fa import views as allauth_2fa_views
app_name = "main"
urlpatterns = [
path("setup/", allauth_2fa_views.TwoFactorSetup.as_view(), name="setup"),
path("", views.homepage, name="homepage"),
path("register/", views.register, name="register"),
path("logout/", views.logout_request, name="logout"),
path("login/", views.login_request, name="login"),
]
The TwoFactorSetup view is using a template setup.html in a folder allauth_2fa. So all you need to do is place your setup.html inside a folder with the same name: app_folder/templates/allauth_2fa/setup.html to override it.
Alternatively, subclass TwoFactorSetup and just change the template_name attribute to point to your template and use that view in your urls.py:
from allauth_2fa.views import TwoFactorSetup
class MySetup(TwoFactorSetup):
template_name = 'my_app/setup.html'

Django : CSRF verification failed even after adding {% csrf_token %}

views.py:
def index(request):
return render_to_response('index.html', {})
def photos(request, artist):
if not artist:
return render_to_response('photos.html', {'error' : 'no artist supplied'})
photos = get_photos_for_artist(artist)
if not photos:
logging.error('Issue while getting photos for artist')
return render_to_response('photos.html', {'error': 'no matching artist found'})
return render_to_response('photos.html', {'photos': photos})
Index.html:
<html>
<head>
<title>find artist photos </title>
</head>
<body>
{% block error %} {% endblock %}
<form action="/photos" method="POST">
{% csrf_token %}
<label for="artist">Artist : </label>
<input type="text" name="artist">
<input type="submit" value="Search">
</form>
{% block content %}{% endblock %}
</body>
</html>
photos.html:
{% extends 'index.html' %}
{% block error %}
{% if error %}
<p> {{ error}} </p>
{% endif %}
{% endblock %}
{% block content %}
{% if photos %}
{% for photo in photos %}
{{ photo }}
{% endfor %}
{% endif %}
{% endblock%}
url.py:
urlpatterns = patterns('',
(r'', index),
(r'^time/$', current_datetime),
(r'^photos/(\w+)$', photos)
)
I even tried by adding {% csrf_token %}, but no luck
Thank you
UPDATE
I see these in the logs
UserWarning: A {% csrf_token %} was used in a template, but the context did not provide the value. This is usually caused by not using RequestContext.
warnings.warn("A {% csrf_token %} was used in a template, but the context did not provide the value. This is usually caused by not using RequestContext.")
This came after adding context_instance=RequestContext(request) **to render_to_response()**
add context_instance=RequestContext(request) to every view that you will use a form inside it:
return render_to_response('index.html', {}, context_instance=RequestContext(request) )
return render_to_response('photos.html', {'photos': photos}, context_instance=RequestContext(request) )
Supposing you are using a fairly recent version of Django (1.3/1.4/dev) you should follow these steps :
In settings.py, Add the middleware django.middleware.csrf.CsrfViewMiddleware to the
MIDDLEWARE_CLASSES list.
In your template, use the {% crsf_token %} in the form.
In your view, ensure that the django.core.context_processors.csrf context processor is used either by :
use RequestContext from django.template
directly import the csrf processor from from django.core.context_processors
Examples
from django.template import RequestContext
from django.shortcuts import render_to_response
def my_view(request):
return render_to_response('my_template.html', {}, context_instance=RequestContext(request))
or
from django.core.context_processors import csrf
from django.shortcuts import render_to_response
def my_view(request):
c = {csrf(request)}
return render_to_response('my_template.html', c)
References
csrf in Django 1.3 or csrf in Django 1.4
RequestContext in Django 1.3 or RequestContext in Django 1.4
(exhaustive post for posterity and future viewers)
A number of things to troubleshoot here:
Please load your "index" page in a web browser, do "View Source", and check if the {% csrf_token %} is being expanded. It should be replaced with an <input> tag. If that's not happening, then you have problems with your index page. If it is being replaced correctly, then you have problems with your photos page.
The POST URL in index.html doesn't match any of the patterns in urls.py. Your urls.py seems to expect the search term to be part of the URL, but it's not - you're sending it as a HTTP POST parameter. You need to access it via request.POST.
Check in the settings, if you have this middleware:
'django.middleware.csrf.CsrfViewMiddleware'
https://docs.djangoproject.com/en/dev/ref/contrib/csrf/
You may need to explicitly pass in a RequestContext instance when you use render_to_response in order to get the CSRF values for that template tag.
http://lincolnloop.com/blog/2008/may/10/getting-requestcontext-your-templates/
Try using the #csrf_protect decorator:
from django.views.decorators.csrf import csrf_protect
from django.shortcuts import render_to_response
#csrf_protect
def photos(request,artist):
if not artist:
return render_to_response('photos.html', {'error' : 'no artist supplied'})
photos = get_photos_for_artist(artist)
if not photos:
logging.error('Issue while getting photos for artist')
return render_to_response('photos.html', {'error': 'no matching artist found'})
return render_to_response('photos.html', {'photos': photos})
This worked for me:
{% csrf_token %}
In the template, there is a {% csrf_token %} template tag inside each POST form that targets an internal URL.
In views.py:
from django.template import RequestContext
...
...
...
return render_to_response("home.html", {}, context_instance=RequestContext(request))

Categories