Reputation: 1713
I have a basic requirement, I have a login page, where after a user logs in, it redirects to a page.
If the user is not logged in, and he opens that url, he gets redirected to the login page and after successful login, he is redirected to the url he opened.
Login : http://127.0.0.1:8000/w_dashboard/login/
Another page : http://127.0.0.1:8000/w_dashboard/roaster/
I have an app named w_dashboard
.
Now in setting page, I have declared
Settings.py
STATIC_URL = '/static/'
LOGIN_URL = '/w_dashboard/login/'
Login.html
<div class="login">
<form action='{% url "login" %}' method="POST">
{% csrf_token %}
<input type="text" placeholder="username" name="user" id="user"><br>
<input type="password" placeholder="password" name="password" id="pwd"><br>
<input type="submit" value="Login">
</form>
<!-- Categories: success (green), info (blue), warning (yellow), danger (red) -->
{% for message in messages %}
<div class="alert alert-{{ category }} alert-dismissible" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span
aria-hidden="true">×</span></button>
<!-- <strong>Title</strong> --> {{ message }}
</div>
{% endfor %}
</div>
w_dashboard's URL file :
from django.urls import path
from . import views
from django.conf.urls import url
urlpatterns = [
#url(r'^$', views.HomePageView.as_view()),
url(r'^$', views.LoginPageView.as_view()),
url(r'^login/$', views.LoginPageView.as_view(), name = 'login'),
url(r'^roaster/$', views.RoasterPageView.as_view(), name="roaster"),
url(r'^manual_login/$', views.RoasterPageView.as_view(), name="mLogin"),
]
Now, w_dashboard
views.py :
class LoginPageView(TemplateView):
def get(self, request, *args, **kwargs):
if request.method == 'GET':
print("Get request")
return render(request, 'login.html', context=None)
def post(self, request, *args, **kwargs):
if request.method == 'POST':
print("POST request")
print(request.POST['user'])
a = models.login_validate(request.POST['user'],request.POST['password'])
if a[0] == 0:
print("inside if ")
messages.error(request, 'username or password not correct')
return render(request, 'login.html', context=None)
elif a[0] == 1:
print("inside elif")
user = emp_user()
user.name = a[1]
print(user.last_login)
print(user.name)
user.save()
login(request, user)
return redirect(request.GET.get('next', 'roaster'))
else:
print("in else")
return render(request, 'login.html', context=None)
class RoasterPageView(TemplateView):
@login_required
def get(self, request, *args, **kwargs):
print(request, request.user)
return render(request, 'roaster.html', context=None)
I have a custom model name emp_user
in w_dashboard
models.py
.
class emp_user(models.Model):
name = models.TextField()
last_login = models.DateTimeField(default=datetime.now)
Now the issue is that am getting following error :
Internal Server Error: /w_dashboard/roaster/
Traceback (most recent call last):
File "/Users/driftking9987/.conda/envs/w_management/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/Users/driftking9987/.conda/envs/w_management/lib/python3.6/site-packages/django/core/handlers/base.py", line 126, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/Users/driftking9987/.conda/envs/w_management/lib/python3.6/site-packages/django/core/handlers/base.py", line 124, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/driftking9987/.conda/envs/w_management/lib/python3.6/site-packages/django/views/generic/base.py", line 68, in view
return self.dispatch(request, *args, **kwargs)
File "/Users/driftking9987/.conda/envs/w_management/lib/python3.6/site-packages/django/views/generic/base.py", line 88, in dispatch
return handler(request, *args, **kwargs)
File "/Users/driftking9987/.conda/envs/w_management/lib/python3.6/site-packages/django/contrib/auth/decorators.py", line 20, in _wrapped_view
if test_func(request.user):
AttributeError: 'RoasterPageView' object has no attribute 'user'
[31/Jan/2019 09:42:42] "GET /w_dashboard/roaster/ HTTP/1.1" 500 72039
Any leads will be helpful. I just want the login page to redirect to roaster page. And if am opening url of roaster, then it should redirect to login and then again to roaster.
I also need the logged in user's name in roaster so that I can display it( am saving the user, but it's not giving the desired output)
And also, if the user logs in, for how long it will be logged in? I mean, let's say I log in and somehow correctly get redirected to roaster page, then if I manually open the roaster page, I shouldn't get redirected to login and for how long this situation can last?
Thanks
Upvotes: 0
Views: 2669
Reputation: 523
from django.contrib.auth.decorators import login_required
# Create your views here.
@login_required(login_url='login')
def dashboard (request):
return render(request, 'dash/index.html')
```
this view only access by the logged in user
Upvotes: 0
Reputation: 1713
This answer is basically for someone who is just starting out, might not be the most optimised code but at least it get's you up and running.
First of all, let's create a custom model in models.py
.
class AuthUser(AbstractBaseUser):
password = models.CharField(max_length=128)
last_login = models.DateTimeField(blank=True, null=True)
is_superuser = models.IntegerField()
username = models.CharField(unique=True, max_length=150)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=150)
email = models.CharField(null=False, unique=True, max_length=254)
is_staff = models.IntegerField()
is_active = models.IntegerField()
date_joined = models.DateTimeField()
USERNAME_FIELD = 'email'
class Meta:
managed = False
db_table = 'auth_user'
Declare it in setting.py
.
STATIC_URL = '/static/'
LOGIN_URL = '/w_dashboard/login/'
AUTH_USER_MODEL = 'w_dashboard.AuthUser'
AUTHENTICATION_BACKENDS = [
'w_dashboard.auth_backends.MySQLAuthBackend',
]
In my case, I had to query the username/password from a mysql table. So I have to make changes accordingly.
First, in settings.py
add your database details.
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'w_s',
'USER': 'r09ot',
'PASSWORD': 'qw5',
'HOST': '119.00.00.000',
'PORT': '3306',
}
}
Now this will create few tables in database, and we will be using the auth_user
table created by Django
to store the username and password.
Now, let's create the custom backend. Create a file named auth_backends.py
.
Add the following code :
from django.contrib.auth import get_user_model, backends
from .models import AuthUser
class MySQLAuthBackend:
def authenticate(self, request, email=None, password=None):
print("inside auth func")
usermodel = get_user_model()
try:
user = usermodel.objects.get(email=email)
if not user:
print("No such user")
else:
print("abc")
if user.password == password:
print("password match")
return user
# if user.check_password(password):
# return user
except usermodel.DoesNotExist:
print("inside except")
return None
def get_user(self, pk):
usermodel = get_user_model()
try:
usermodel = get_user_model()
return usermodel.objects.get(pk=pk)
except usermodel.DoesNotExist:
pass
return None
The above code will query the database with username as "email" and password as "password". And return the user.
Now let's come to Login function.
def post(self, request, *args, **kwargs):
if request.method == 'POST':
print("POST request")
print(request.POST['user'])
user = authenticate(request, email=request.POST['user'], password=request.POST['password'])
if user is not None:
print("login success")
user.save()
print(user.__dict__)
login(request, user)
request.session.set_expiry(20)
return redirect(request.GET.get('next', 'mLogin'))
else:
print("login unsuccess")
messages.error(request, 'username or password not correct')
return render(request, 'login.html', context=None)
Now this is the most important part. Since we authenticated the user from custom backend authentication method, user
is being populated in a way which is acceptable to login
method to accept. In a nutshell, it let's you login into the login
function.
Now comes the part of login_required
. Since it's a view, we will use method_decorator
like this :
@method_decorator(login_required, name='dispatch')
class ManualLoginPageView(TemplateView):
def get(self, request, *args, **kwargs):
print("inside manual login")
print(request.user.__dict__)
print(request.user.get_short_name())
return render(request, 'manualLogin.html', context=None)
Also in url.py
, Add login_required
like
url(r'^roaster/$', login_required(views.RoasterPageView.as_view()), name="roaster"),
This is working and executing the functionalities as intended.
Upvotes: 0
Reputation: 1084
The auth decorators should be used for functions (not methods in the class). For class-based views, you should use mixins like LoginRequiredMixin
. More information with samples can be found in official Django documentation - https://docs.djangoproject.com/en/2.1/topics/auth/default/
EDIT: You are also using custom model for a user - how to implement custom user or extend user model used by Django auth can be found here: https://docs.djangoproject.com/en/2.1/topics/auth/customizing/
Upvotes: 0