03 用户登陆的常见模块和使用
next在登陆页面的妙用
在用户的登陆页面判断url中是否含有next参数,如果有则跳转到,登陆前的url:
常用的是在登陆的LoginView处理函数中,把以下的代码添加和修改局部的登陆函数:
# 判断页面url中是否有next参数, next = request.GET.get("next") # 如果有,则跳转到next的url if next: return redirect(next) else: # 如果没有,跳转到主页 return redirect(reverse("goods:index"))
完整代码:
class LoginView(View): """登录""" def get(self, request): """提供登录页面""" return render(request, "login.html") def post(self, request): """处理登录的数据""" # 获取参数 user_name = request.POST.get("username") password = request.POST.get("pwd") remembered = request.POST.get("remembered") # 记住用户名的参数 # 参数校验 if not all([user_name, password]): # 参数不完整 return render(request, "login.html") # 登录业务逻辑处理 # try: # password = sha256(password) # User.objects.get(username=user_name, password=password) # except User.DoesNotExist: # return HttpResponse("用户名或密码错误") # 使用django的认证系统进行用户密码的校验 user = authenticate(username=user_name, password=password) if user is None: # 用户的登录信息有误 return render(request, "login.html", {"errmsg": "用户名或密码错误!"}) # 判断用户的激活状态 if user.is_active is False: return render(request, "login.html", {"errmsg": "用户尚未激活!"}) # 保存用户的登录状态 # 使用django的login函数保存用户的session数据 login(request, user) # 根据用户勾选的记住用户名选项,设置session数据的有效期(django帮助我们完成cookie有效期的设置) if remembered != "on": # 表示用户没有勾选 request.session.set_expiry(0) # 设置为临时会话 else: # 表示用户勾选 request.session.set_expiry(None) # 采用django的默认设置有效期 # 登录成功, # 判断页面url中是否有next参数, next = request.GET.get("next") # 如果有,则跳转到next的url if next: return redirect(next) else: # 如果没有,跳转到主页 return redirect(reverse("goods:index"))
在下面的页面中的url改为:
http://127.0.0.1:8000/users/login
用户就跳转到了登陆的页面:
在用户输入完,用户和密码后会跳转到原来的网页:
====================================================================================================================
如何退出一个用户
若要退出一个已经通过django.contrib.auth.login()登入的用户,可以在你的视图中使用django.contrib.auth.logout()。 它接收一个HttpRequest对象且没有返回值
定义退出是请求的处理函数:
from django.contrib.auth import authenticate, login, logout class LogoutView(View): """退出""" def get(self, request): # 使用django的认证系统提供的logout函数,清除session数据 logout(request) # 跳转到主页 return redirect(reverse("goods:index"))
定义退出的请求路径:
url(r'^logout$', views.LogoutView.as_view(), name="logout"),
在任一个登陆过的页面都有登陆过的session信息,如下图:
在上面途中的地址栏中填写退出登陆的url:
http://127.0.0.1:8000/users/logout
session清除掉了,并且重定向到了指定的网页
=============================================================================================================
只允许登录的用户访问
login_required 装饰器,login_required([redirect_field_name=REDIRECT_FIELD_NAME, login_url=None])
作为一个快捷方式,你可以使用便捷的login_required()装饰器:
from django.contrib.auth.decorators import login_required
@login_required(redirect_field_name='my_redirect_field')
def my_view(request):
...
login_required()完成下面的事情:
- 如果用户没有登入,则重定向到settings.LOGIN_URL,并将当前访问的绝对路径传递到查询字符串中。例如:/accounts/login/?next=/polls/3/。
- 如果用户已经登入,则正常执行视图。视图的代码可以安全地假设用户已经登入。
默认情况下,在成功认证后用户应该被重定向的路径存储在查询字符串的一个叫做"next"的参数中。如果对该参数你倾向使用一个不同的名字,login_required()带有一个可选的redirect_field_name参数:
Django认证系统文档:http://python.usyiyi.cn/documents/django_182/topics/auth/default.html
自定义一个给所有只允许登陆过的用户访问的基类,在utils包中创建文件views.py
因为我用的到时类视图,所以我重构了as_view方法,用login_required装饰as_view编写如下的代码:,
from django.contrib.auth.decorators import login_required class LoginRequiredMixin(object): """要求用户登录的功能补充逻辑""" @classmethod def as_view(cls, **initkwargs): view = super(LoginRequiredMixin, cls).as_view(**initkwargs) # 实际上就是调用的django提供的类视图基类的as_view return login_required(view)
定义地址信息的请求处理函数,并且只有登陆过的用户才可以访问,导入自定义的限制访问的基类 from utils.views import LoginRequiredMixin
from utils.views import LoginRequiredMixin class AddressView(LoginRequiredMixin, View): """用户地址""" return render(request, "user_center_site.html", context)
在应用users中添加地址信息的url
url(r'^address$', views.AddressView.as_view(), name="address"),
在配置文件中,用户没有登陆重定向的页面:
LOGIN_URL = '/users/login'
没登陆的用来直接访问返回到登陆的页面
http://127.0.0.1:8000/users/address
用户登陆后在地址栏中输入:
http://127.0.0.1:8000/users/address
显示的页面如下:
在Address中get 方法中给传用户的地址信息进行渲染,request请求中包含了用户的信息,我们可以直接调用request.user获取当前的对象user
通过当前的user表查到最新的地址信息表user.address_set.latest("create_time")
class AddressView(LoginRequiredMixin, View): """用户地址""" def get(self, request): """提供用户地址页面""" user = request.user #登录的用户对象 # 获取用户的地址信息,按照创建时间选择最新的一条 try: address = user.address_set.latest("create_time") except Address.DoesNotExist: address = None context = { # "user": user, # 这个数据可以不用传,在的django中可以直接使用 "address": address } # 渲染模板 return render(request, "user_center_site.html", context)
在Address中post方法中让用户修改最新的地址信息进行渲染:
def post(self, request): """维护地址信息""" user = request.user recv_name = request.POST.get("recv_name") addr = request.POST.get("addr") zip_code = request.POST.get("zip_code") recv_mobile = request.POST.get("recv_mobile") if all([recv_name, addr, zip_code, recv_mobile]): # address = Address( # user=user, # receiver_name=recv_name, # detail_addr=addr, # zip_code=zip_code, # receiver_mobile=recv_mobile # ) # address.save() Address.objects.create( user=user, receiver_name=recv_name, detail_addr=addr, zip_code=zip_code, receiver_mobile=recv_mobile ) return redirect(reverse("users:address"))
随便填写提交的返回页面如下: