How to pass the logged in user to direct_to_template? - django

I'm using direct_to_template for a url but I need the logged in user to display the page. How do I pass it to direct_to_template?

If your TEMPLATE_CONTEXT_PROCESSORS variable in settings.py is set to include 'django.contrib.auth.context_processors.auth', it will already be on the page context. (This is configured by default).
The direct_to_template generic view uses RequestContext, so there will be a context variable called user that will provide the currently logged in user (or an AnonymousUser if there is no logged in user).
For example, to display the username in your template: {{ user.username }}.
For more details see the django docs on the auth context processor.

put following in your login view before GET method
def custom_proc(request):
return {
'app': 'myapp',
'user': request.user,
'ip_address': request.META['REMOTE_ADDR']
}
in login view in post
......some code here......
return render(request, 'html file name',
context_instance=RequestContext(request,processors=custom_proc]))
in setting.py
TEMPLATE_CONTEXT_PROCESSORS = ( 'django.contrib.auth.context_processors.auth',
'django.core.context_processors.request',
)
and in html file
Hello, username = {{ user.username }} id ={{ user.id }}

Related

Login Required Mixin acting up on a view where i didn't even include it(django)

So, i want my website's content only to be visible to the registered users, so i have put "LoginRequiredMixin" amd "#login_required" tags on most of my views except login and register views. Now, for registration, i want to give the registrants a choice before registering (whether they are current university students or alumni/recent graduates), this is how i am doing this:
class choice(View):
template = "network/choice.html"
def get(self, request):
form = ChoiceForm()
return render(request, self.template, {
"form": form,
"message": "Are you a curent student or an alumni/about to graduate"
})
def post(self, request):
form = ChoiceForm(request.POST)
if form.is_valid():
current = form.cleaned_data["current"]
if current:
return HttpResponseRedirect('accounts/register/current')
else:
return HttpResponseRedirect('accounts/register/alum')
where ChoiceForm just contains a boolean field, and "register/str:type" is my registration URL.
But after i submit the Choice Form:
<form action="{% url 'network:choice' %}" method="post">
{% csrf_token %}
{{ form|crispy }}
<br>
<input type="submit" value="Proceed"
</form>
the url to which i am taken to is:
/accounts/login/?next=/register/current
(i have not included any authentication check on the registration view, that won't make any sense lol)
Where i might have gone wrong is:
because i want anyone truing to access a restricted page to be redirected to the login page, i have defined my Urlpattern as follows:
path('accounts/login/', views.login_view.as_view(), name="login_view"),
path('accounts/register/<str:type>', views.register.as_view(), name="register"),
where 'accounts/login' is the path which django redirects to with the login_required tag. Did i do something wrong here?
This is my register view, although i am pretty sure that's not where the problem is as this view isn't even loading up even if i type in the url 'register/current'. I am still being redirected to accounts/login/?next=/register/current
Urlpatterns:
path('', views.index, name='index'),
path('new/<str:type>', views.new_page.as_view(), name="new"),
path('<str:type>/<str:name>', views.page.as_view(), name="page"),
path('logout', views.logout_view, name="logout_view"),
path('accounts/login/', views.login_view.as_view(), name="login_view"),
path('accounts/register/<str:type>', views.register.as_view(), name="register"),
path('choice', views.choice.as_view(), name="choice"),

How to redirect to a page after successful login and implement tokens within the templates in Django?

I am completely new to using JWT authentication in Django and don't know how to implement tokens within each template of my application. I am using JWT (JSON Web Tokens) instead of sessions.
Scenario:
I have a login form that uses AJAX where after clicking the submit button, it points to my API and takes the credentials of a registered user. If authenticated, I intend to use JWT authentication and access the dashboard page, and include those tokens within the page (instead of using sessions). However, I am not redirecting to the specified URL after logging in. Furthermore, I have used Simple-JWT in order to generate tokens but don't know how to include them in my template (AJAX call) in order to access an API. I have tried the following:
views.py:
I have created a login form that doesnt access the values.
Instead, I have used AJAX in my template in order to point it towards the LoginAPI below:
def login(request):
if request.method == 'POST':
login_form = LoginForm(request.POST)
if login_form.is_valid():
pass #not doing anything here since all I need is a form for logging in.
else:
login_form = LoginForm()
return render(request, "users/login.html", {"login_form" : login_form})
#Login API that gets called after clicking the form submit button.
class LoginAPI(APIView):
permission_classes = [AllowAny]
def post(self, request, format = None):
username = request.data['username']
password = request.data['password']
new_user = authenticate(username = username, password = password)
if new_user is not None:
url = 'http://localhost:8000/api/token/' #need to pass in the credentials in order to access the JWT tokens.
values = {
'username' : username,
'password' : password
}
r = requests.post(url, data = values)
token_data = r.json()
return Response(token_data) #should return the JSON tokens to AJAX in success function.
else:
return Response({"status" : "Denied."}, status=status.HTTP_400_BAD_REQUEST)
forms.py:
class LoginForm(forms.Form):
username = forms.CharField()
password = forms.CharField(widget=forms.PasswordInput)
urls.py:
from users import views as users_views
from django.conf import settings
from django.conf.urls.static import static
from users.views import LoginAPI
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
urlpatterns = [
path('admin/', admin.site.urls),
path('login_api/', LoginAPI.as_view(), name = 'login_api'),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('login/', user_views.login, name = 'login'),
]
login.html:
{% extends 'users/base.html' %}
{% load static %}
{% block javascript %}
<script src='{% static "users/js/main.js" %}'></script>
{% endblock %}
{% block content %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
{{ login_form|crispy }}
<div class="form-group">
<button class="btn btn-outline-info" type="submit" id='login'> Login </button>
</div>
</form>
</div>
{% endblock content %}
main.js (the file that contains the AJAX function):
$('#login').click(function () {
var username = $('#username').val();
var password = $('#password').val();
$.ajax({
cache: false,
method: 'POST',
url: "/login_api/", #After click, the URL should point towards the LoginAPI in views.py
data: {username:username, password: password},
datatype: 'json',
success: function(data) {
console.log(data.access);
localStorage.setItem('access', data.access);
window.location.href = 'http://127.0.0.1:8000/punch_funcs'; #the template I wish to go to after successful logging in.
},
When testing the login form, I found out that I am being redirected to my template 'punch_funcs'. But the URL is the same as my login page which means that whenever I refresh the page, I am taken back to my login template:
'http://localhost:8000/login' this should be 'http://localhost:8000/punch_funcs' instead.
Also, the tokens have been generated successfully, but how can I place this within my 'punch_funcs' template in order to access several APIs (not listed in the code above)?
Any help is highly appreciated. Thank you very much.

Sending context with request, and {% if %} not working properly

I have a problem trying to figure out why below will render an html page showing 'hi' and 1, instead of just 1.
views method.
def index(request):
context = {
'test' : 1,
}
return render(request, 'index.html', context)
template html. Rendering index.html will show both 'hi' and 1. But there's no user in context, so why is the if user going through?
{% if user %}
<h1>hi</h1>
{% endif %}
{% if test %}
<h1>{{ test }}</h1>
{% endif %}
The answer is Django's builtin context processor called django.contrib.auth.context_processors.auth. It is enabled by default which means an auth.User object representing the currently logged-in user is sent to all templates with the name user automatically.
From docs:
The context_processors option is a list of callables – called context processors – that take a request object as their argument and return a dictionary of items to be merged into the context.
In the default generated settings file, the default template engine contains the following context processors:
[
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
]
if there is a user logged in django will create a AUTH_USER_MODEL representing the currently logged-in user. Also from the request object you can access the user model without specifying context. For example if a user is logged in you can do request.user.username and the username will appear in the template.

How to customize django rest auth password reset email content/template

In django rest_auth password reset, default email content look like following:-
You're receiving this email because you requested a password reset for your user account at localhost:8000.
Please go to the following page and choose a new password:
http://localhost:8000/api/reset/Kih/89a-23809182347689312b123/
Your username, in case you've forgotten: test
Thanks for using our site!
The localhost:8000 team
How to customize content of this email ?
I recently needed to implement the same thing in one of my projects and could not find a thorough answer anywhere.
So I'm leaving my solution here for anyone who needs it in the future.
Expanding on mariodev's suggestion:
1. Subclass PasswordResetSerializer and override save method.
yourproject_app/serializers.py
from django.conf import settings
from rest_auth.serializers import PasswordResetSerializer as _PasswordResetSerializer
class PasswordResetSerializer(_PasswordResetSerializer):
def save(self):
request = self.context.get('request')
opts = {
'use_https': request.is_secure(),
'from_email': getattr(settings, 'DEFAULT_FROM_EMAIL'),
###### USE YOUR TEXT FILE ######
'email_template_name': 'example_message.txt',
'request': request,
}
self.reset_form.save(**opts)
2. Configure AUTH_USER_MODEL
yourproject/settings.py
###### USE YOUR USER MODEL ######
AUTH_USER_MODEL = 'yourproject_app.ExampleUser'
3. Connect custom PasswordResetSerializer to override default
yourproject/settings.py
REST_AUTH_SERIALIZERS = {
'PASSWORD_RESET_SERIALIZER':
'yourproject_app.serializers.PasswordResetSerializer',
}
4. Add the path to the directory where your custom email message text file is located to TEMPLATES
yourproject/settings.py
TEMPLATES = [
{
...
'DIRS': [os.path.join(BASE_DIR, 'yourproject/templates')],
...
}
]
5. Write custom email message (default copied from Django)
yourproject/templates/example_message.txt
{% load i18n %}{% autoescape off %}
{% blocktrans %}You're receiving this email because you requested a password reset
for your user account at {{ site_name }}.{% endblocktrans %}
{% trans "Please go to the following page and choose a new password:" %}
{% block reset_link %}
{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}
{% endblock %}
{% trans "Your username, in case you've forgotten:" %} {{ user.get_username }}
{% trans "Thanks for using our site!" %}
{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
{% endautoescape %}
UPDATE: This solution was written for an older version of django-rest-auth (v0.6.0). As I can tell from the comments, it seems there have been some updates made to the source package that more readily handle custom email templates out-of-box. It is always better to use methods defined in a package rather than overriding them like in my solution. Though once a necessity, it may not be so any longer.
You can inherit PasswordResetSerializer and override the get_email_options method. For example:
from rest_auth.serializers import PasswordResetSerializer
class CustomPasswordResetSerializer(PasswordResetSerializer):
def get_email_options(self):
return {
'subject_template_name': 'registration/password_reset_subject.txt',
'email_template_name': 'registration/password_reset_message.txt',
'html_email_template_name': 'registration/'
'password_reset_message.html',
'extra_email_context': {
'pass_reset_obj': self.your_extra_reset_obj
}
}
You need to hook up your own reset password serializer (PASSWORD_RESET_SERIALIZER) with customized save method.
(ref: https://github.com/Tivix/django-rest-auth/blob/v0.6.0/rest_auth/serializers.py#L123)
Unfortunately you need to override the whole save method, due to how the e-mail options are used. We we'll make it a bit more flexible in the next release (0.7.0)
A simple solution is
Create over templates directory:
-templates
-registration
password_reset_email.html
with content you want.
Django rest-auth use django.contrib.auth templates.
So for the dj-rest-auth, this is how I did it:
from django.contrib.auth.tokens import default_token_generator
from django.contrib.sites.shortcuts import get_current_site
from django.urls.base import reverse
from allauth.account import app_settings
from allauth.account.adapter import get_adapter
from allauth.account.utils import user_pk_to_url_str, user_username
from allauth.utils import build_absolute_uri
from dj_rest_auth.forms import AllAuthPasswordResetForm
from dj_rest_auth.serializers import PasswordResetSerializer
class CustomAllAuthPasswordResetForm(AllAuthPasswordResetForm):
def save(self, request, **kwargs):
current_site = get_current_site(request)
email = self.cleaned_data['email']
token_generator = kwargs.get('token_generator',
default_token_generator)
for user in self.users:
temp_key = token_generator.make_token(user)
# save it to the password reset model
# password_reset = PasswordReset(user=user, temp_key=temp_key)
# password_reset.save()
# send the password reset email
path = reverse(
'password_reset_confirm',
args=[user_pk_to_url_str(user), temp_key],
)
url = build_absolute_uri(None, path) # PASS NONE INSTEAD OF REQUEST
context = {
'current_site': current_site,
'user': user,
'password_reset_url': url,
'request': request,
}
if app_settings.AUTHENTICATION_METHOD != app_settings.AuthenticationMethod.EMAIL:
context['username'] = user_username(user)
get_adapter(request).send_mail('account/email/password_reset_key',
email, context)
return self.cleaned_data['email']
class CustomPasswordResetSerializer(PasswordResetSerializer):
#property
def password_reset_form_class(self):
return CustomAllAuthPasswordResetForm
# settings.py
REST_AUTH_SERIALIZERS = {
'PASSWORD_RESET_SERIALIZER':
'api.users.api.serializers.CustomPasswordResetSerializer',
}
By passing None to build_absolute_uri instead of the original request, it will take the value you have in django.contrib.sites module with SITE_ID=1. So whatever you have defined as your domain in the Django admin will now be the domain in the reset URL. This makes sense if you want to have the password reset URL point to your frontend, that might be a React application running on a different domain.
Edit:
My PR regarding this issue was merged, with the next release this will be possible to set in your settings. Checkout the docs for dj-rest-auth to see which setting you need to set.
if you want to use a html email template, an update to Brian's answer would be to add
'html_email_template_name': 'account/email/example_message.html',
just below
###### USE YOUR TEXT FILE ######
'email_template_name': 'account/email/example_message.txt',
this way you can the email with a html template
You can see why this happens by inspecting the send_mail method of the PasswordResetForm class
class PasswordResetForm(forms.Form):
email = forms.EmailField(label=_("Email"), max_length=254)
def send_mail(self, subject_template_name, email_template_name,
context, from_email, to_email, html_email_template_name=None):
"""
Send a django.core.mail.EmailMultiAlternatives to `to_email`.
"""
subject = loader.render_to_string(subject_template_name, context)
# Email subject *must not* contain newlines
subject = ''.join(subject.splitlines())
body = loader.render_to_string(email_template_name, context)
email_message = EmailMultiAlternatives(subject, body, from_email, [to_email])
if html_email_template_name is not None:
html_email = loader.render_to_string(html_email_template_name, context)
email_message.attach_alternative(html_email, 'text/html')
email_message.send()```
Create directory with path as following in your template folder
templates/admin/registration/
Now copy all files in django/contrib/admin/templates/registration/ into this directory you just created. You can find this directory where you have installed django. In linux, it can be find here
/usr/local/lib/python2.7/dist-packages/django/contrib/admin/templates/registration
You will need root priviliges for accessing this.
Now when you will send email, templates in you just copied in your project will be used.
This link might be helpful. With it I was able to find where the email templates were and how to customize them.
You can find the info at the bottom of the page under
Customize the email message
http://www.sarahhagstrom.com/2013/09/the-missing-django-allauth-tutorial/#Customize_the_email_message

Django request.user.username doesn't work

Hi
I've got a problem with the Django Template system. When I want to check in the template if a user is logged in with:
{% if user.is_authenticated %}
# success
{% else %}
<p>Welcome, new user. Please log in.</p>
{% endif %}
I dont get to the success part. When I use in a view:
if not request.user.is_authenticated():
return render_to_response('index.html', {'inhalt': 'Not loggged in'})
else:
return render_to_response('index.html', {'inhalt': 'Succesfully loged in'})
it shows me correctly the else part.
Hope somebody can help me.
Thanks Phil
There is an example of handling the context in part 4 of the Django tutorial. However, in short...
The best way to do this is with Django's auth context proccessor. Make sure you still have it in your settings. You then need to use RequestContext
This will essentially change your code to this.
from django.template import RequestContext
# ...
return render_to_response('index.html', {
'inhalt': 'Succesfully loged in'
}, RequestContext(request))
Remember to add 'django.core.context_processors.request' to your TEMPLATE_CONTEXT_PROCESSORS in your settings.py
Example:
# Context processors
TEMPLATE_CONTEXT_PROCESSORS = (
'django.contrib.auth.context_processors.auth',
'django.core.context_processors.debug',
'django.core.context_processors.i18n',
'django.core.context_processors.media',
'django.core.context_processors.static',
'django.core.context_processors.request',
'django.contrib.messages.context_processors.messages',
)
And add RequestContext(request):
# import
from django.template import RequestContext
# render
if not request.user.is_authenticated():
return render_to_response('index.html', {'inhalt': 'Not loggged in'})
else:
return render_to_response('index.html', {'inhalt': 'Succesfully logged in'}, RequestContext(request))
In your python you retrieve the user object that is logged in. I.e define a function get_current_user.
so your response would look something like:
class Index(webapp.RequestHandler):
def get(self):
user= get_current_user()
templates.render(self, 'mypage.html', user=user)
Then on your django template you can simply go like:
{% if user %}
<p>Hallo user {{user.name}}</p>
{% else %}
<p>Welcome, new user. Please log in.</p>
{% endif %}
You need to make sure that either you pass 'request.user' into the renderer. Or better yet use context based rendering:
return render_to_response('index.html',
my_data_dictionary,
context_instance=RequestContext(request))
The context_instance will use the auth middleware context processor to set the 'user' in your view.
Did you pass in your "user" instance from the view to the template? You need to make sure it is in the same context you pass into the render_to_response(), or whichever rendering method you choose for rendering the view context into the template.