Django admin: how to pass top bar notification - django

When you save something via django admin you will get this bootstrap alert bar at the top of your page saying "save" or "please correct errors". How do I pass something in get/post parameters to be displayed in such bar?

You're looking for Django's Messaging Framework.
Here's some code from the docs:
from django.contrib import messages
messages.add_message(request, messages.INFO, 'Hello world.')
# Shortcut methods
messages.debug(request, '%s SQL statements were executed.' % count)
messages.info(request, 'Three credits remain in your account.')
messages.success(request, 'Profile details updated.')
messages.warning(request, 'Your account expires in three days.')
messages.error(request, 'Document deleted.')

Related

how to use django message framework for #login_required to show message

I am using #login required decorator in my most of views so what I want is to use message in my login page telling user if you want to open that page you have to login first so how I can achieve that I know I cannot achieve that on my views so anyone does that and know how to do please tell me how to achieve that if a user redirected to login because of #login required I want to show message please login to continue
I also looked on some of the same question I am looking for answer which got implemented on all the login required decorator so I don't have to change code everywhere it already got implemented in all of the login required decorator in my whole app
my login view
def my_login(request):
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
username = form.cleaned_data["username"]
password = form.cleaned_data["password"]
remember_me = form.cleaned_data['remember_me']
user = authenticate(username=username, password=password)
if user:
login(request, user)
if not remember_me:
request.session.set_expiry(0)
return redirect('accounts:home')
else:
request.session.set_expiry(1209600)
return redirect('accounts:home')
else:
return redirect('accounts:login')
else:
return redirect('accounts:register')
else:
form = LoginForm()
return render(request, "login.html", {'form': form})
Solution 1:
In your view, check the query parameter "next", as if the user is redirected to the login view, it would come with the ?next=/whatever in the URL. You can do
if 'next' in request.GET:
messages.add_message(request, messages.INFO, 'Hello world.')
Solution 2 (not recommended, this makes it confusing to debug for others):
Python being a dynamic language, you can hijack the behaviour of login_required with your version.
in your manage.py and wsgi.py and maybe asgi.py you would need to "monkey patch" the login_required decorator.
from django.contrib.auth import decorators
def my_login_required(...):
# you can look at the implementation in the answer by LvanderRee mentioned in the comments
decorators.login_required = my_login_required
Now, because these files will be the first code to execute before Django even starts, this will replace the built-in login_required with your version.
Based on this Stack Overflow post, using multiple answers, to redirect to another page, either:
Set LOGIN_URL in settings.py. This is the URL that Django will redirect to if a user that's not yet logged in attempts to log in.
or Inline:
from django.contrib.auth.decorators import login_required
#login_required(login_url='/example url you want redirect/') #redirect when user is not logged in
def myview(request):
do something
return something #returns when user is logged in
Of course, you still need to have the login view setup.
If you want to check if the user is authenticated in the HTML, you can use the templating system: (For clarity this is something I just whipped up right now, it's not from the Stack Overflow post mentioned above)
{% if user.is_authenticated %}
// Display something if authenticated maybe
{% else %}
// Display something like "You are not logged in etc"
{% endif %}

Confirm Form Resubmission with Context Required Django

I have an account page that lets users edit their accounts. When the save button is pressed, I run the following code:
request.user.first_name = request.POST['first_name']
request.user.last_name = request.POST['last_name']
request.user.save()
context['alert'] = {
'title': "Your information has been updated",
'color': 'primary',
}
As you can see, I pass in context that, in my template, renders as an alert. However, when I refresh the page, it says: Confirm Form Resubmission
How can I get rid of this error? Thanks!
A successful POST request normally results in a redirect, this is the so-called Post/Redirect/Get pattern [wiki].
In order to send messages to the user, you can make use of the messaging framework [Django-doc]. So you can add a message for a user, and then render it in the other view(s):
from django.shortcuts import redirect
from django.contrib import messages
def my_view(request):
request.user.first_name = request.POST['first_name']
request.user.last_name = request.POST['last_name']
request.user.save()
messages.success(request, 'Your information has been updated')
return redirect('name-of-some-view')

Force password change on first login (Django)

A client requires the ability for managers to add users to a company (with a random one time password) where the user must change their password before accessing anything. I am developing the app in Django 2.2
I made a custom user, replacing username with an email address and I added a change_password bool flag to the user. My change_password form/function works properly, but redirecting does not.
urls.py
path('change-password/', views.change_password, name='change-password'),
views.py
class Login(LoginView):
def form_valid(self, form):
# form is valid (= correct password), now check if user requires to set own password
if form.get_user().change_password:
return HttpResponseRedirect(reverse('change-password'))
else:
auth_login(self.request, form.get_user())
return HttpResponseRedirect(self.get_success_url())
def change_password(request):
if request.method == 'POST':
form = PasswordChangeForm(data=request.POST, user=request.user)
if form.is_valid():
form.save()
request.user.change_password = False
request.user.save()
update_session_auth_hash(request, request.user)
return redirect(reverse('user_view'))
else:
return redirect(reverse('change-password'))
else:
form = PasswordChangeForm(user=request.user)
args = {'form': form}
return render(request, 'users/change_password.html', args)
The expected behavior is to redirect to change-password if the change_password flag is True, however, while the app does redirect to change-password, upon Submission the following error is thrown:
NotImplementedError: Django doesn't provide a DB representation for AnonymousUser.
If I add the decorator #login_required to my change_password function this error goes away, however, I am redirected back to the login page with the URL: users/login/?next=/users/change-password/
The problem is that in form_valid method you are calling form.get_user() which authenticates/gets the user and checks for the change_password correctly, but it does not log the user in, meaning that the user making the requests is still anonymous to the system. So while the user gets redirected they are not authenticated, which means that the request.user objects is of type AnonymousUser which does not live in the database hence the Django doesn't provide a DB representation for AnonymousUser error.
And when you use the #login_required decorator the user gets redirected to the login page because it is not a logged in user and the decorator requires the user to be logged in to see the view it is decorating.
The URL that you see users/login/?next=/users/change-password/ is basically how the login_required decorator works and it is doing two things:
1. redirect anonymous user to the login page (the users/login part of the URL)
2. once they have successfully logged in redirect them back from where they came from (?next=/users/change-password/)
My suggestion is that you pass the username of the user that tried to log in but has to change their password to the change_password view and have a form waiting for the user there that asks for the current password, new one and a confirmation of the new password. It is the simplest way to do what you want to do, but you will have to confirm that the users current password is correct again though.
Sorry for the confusing first answer, I didn't read the question right the first time, hopefully this makes more sense :)

Can I check if a user is logged in for the first time after this user is logged in? - Django

I'm trying to catch the first time someone logs in so I can redirect him/her to another page then normally.
I'm working with groups. A admin can make a group with multiple users (with generated usernames and passwords). So it can be that a user is already created before the user logs in (There is no register form for just one user)
This is the code that I want:
def index(request):
if request.user:
user = request.user
if user.last_login is None:
return redirect('profile')
else:
return redirect('home')
else:
return redirect('/login')
I've read about checking user.last_login but for this case that doesn't work because it checks this method AFTER the user logs in. Which means that user.last_login is never None.
Can someone help me how can see when a user logs in for the first time?
The last_login value is set via a signal which happens at login, but before your code executes, so you never see None as you've discovered.
One way to achieve what you want could be to register your own signal receiver to set a first_login attribute somewhere, e.g. in the user's session, before updating the last_login value.
from django.contrib.auth.signals import user_logged_in
from django.contrib.auth.models import update_last_login
def update_first_login(sender, user, **kwargs):
if user.last_login is None:
# First time this user has logged in
kwargs['request'].session['first_login'] = True
# Update the last_login value as normal
update_last_login(sender, user, **kwargs)
user_logged_in.disconnect(update_last_login)
user_logged_in.connect(update_first_login)
Then in your view, you'd just need to check the session for the first_login attribute.
def index(request):
if request.user:
if request.session.get('first_login'):
return redirect('profile')
else:
return redirect('home')
else:
return redirect('/login')
It was a big problem to me at once but i found a way to do it easy.
Make a different variable to save the value of the users logged in data, when user is trying to login.
Check my code:
if user.last_login is None:
auth.login(request,user)
return redirect(alertPassword)
# when user is login for the first time it will pass a value
else:
auth.login(request,user)
return redirect(moveToLogin)
def moveToLogin(request):
return render(request,"home.html")
def alertPassword(request):
first_login=True
return render(request,"home.html",{"first_login":first_login})
#it will pass a value to the template called first login is True
#then go to your template and add this
{% if first_login==True%}
#put any thing you want to be done
#in my case i wanted to open a new window by using script
<script>
window.open("popUpWindow")
</script>
{%endif%}

How to display the message in django admin

I tried to display the message in django admin by using print method, but do not display the message.
Can you help me to display the message in Django admin by using condition?
Show messages in django
messages.debug(request, '%s SQL statements were executed.' % count)
messages.info(request, 'Three credits remain in your account.')
messages.success(request, 'Profile details updated.')
messages.warning(request, 'Your account expires in three days.')
messages.error(request, 'Document deleted.')
You need to study django message docs