django练手( 十二):实现网站的登录功能

一、编写登录页面的form类。

  1. 在app-form-app-account.py 文件中导入auth组件的authenticate方法和login方法。authenticate方法的作用是”验证用户名密码是否匹配。若匹配,会返回user对象“,这个对象会在接下来的login方法中使用。login方法接收一个request对象,一个经过认证的user对象。该方法执行后,会在后端为该用户产生session数据。

  2. 导入authenticate方法和login方法的代码是:from django.contrib.auth import authenticate, login

  3. 代码如下:

     class LoginForm(forms.Form):
     """
     登录Form的功能:
     1、生成登录表单。该表单包含用户名和密码两个字段;
     2、对表单数据进行验证。
     3、重写父类的__init__方法,增加request参数,从视图获取request。
     4、用户名,密码验证通过后,通过auth组件的login方法,实现用户登录。
     """
     username = forms.CharField(max_length=25, label='用户名', required=True,
     						   error_messages={"required": "用户名不能为空",
     										   "max_length": "用户名不能超过25个字符"})
     password = forms.CharField(widget=forms.PasswordInput(), label='密码', required=True, min_length=8,
     						   error_messages={"required": "密码不能为空", "min_length": "密码小于8个字符,请重新输入"})
    
     # 重新父类的__init__方法,从视图获取request数据,是LoginForm可以传进来request
     def __init__(self, request, *args, **kwargs):
     	super().__init__(*args, **kwargs)
     	self.request = request
     	# 给表单加上bootstrap的样式
     	for name, field in self.fields.items():
     		field.widget.attrs['class'] = "form-control"
     		field.widget.attrs['placeholder'] = '请输入{}'.format(field.label)
    
     # 验证用户名是否存在
     def clean_username(self):
     	username = self.cleaned_data['username']
     	exists = MyUser.objects.filter(username=username).exists()
     	if not exists:
     		raise ValidationError('用户名不存在,请重新输入')
     	return username
    
     # 验证密码
     def clean_password(self):
     	password = self.cleaned_data['password']
     	username = self.cleaned_data.get('username', '')
     	# 使用auth组件的authenticate功能,验证用户名密码是否匹配。若匹配,会返回user对象
     	user = authenticate(username=username, password=password)
     	# 如果user对象为空,则返回错误信息”用户名或密码不正确“
     	if user is None:
     		raise ValidationError('用户名或密码不正确')
     	# 如果user对象存在,使用auth组件的login方法,进行登录。该方法接收一个request对象,一个经过认证的user对象。
     	# login方法执行后,会在后端为该用户产生session数据
     	else:
     		login(request=self.request, user=user)
     	return password
    

二、编写登录页面的视图。

  1. 登录视图的代码如下:

     # 登录视图
     def login_view(request):
     	"""
     	功能描述:
     	1、如果是GET方法访问该视图,返回登录表单。
     	2、如果是POST方法访问该视图,则用LoginForm进行数据验证,如果验证通过,进入登录状态。如果验证不通过,返回错误信息。
     	"""
     	if request.method == 'GET':
     		fields = LoginForm(request)
     		return render(request, 'app/login.html', {'fields': fields})
     	if request.method == 'POST':
     		data = request.POST
     		fields = LoginForm(request, data)
     		if fields.is_valid():
     			return JsonResponse({"status": True})
     		else:
     			return JsonResponse({"status": False, "errors": fields.errors})
    

三、登录页面的模板设计。

  1. 登录页面的模板与注册页面的模板几乎完全一样,不做详细解释,代码如下:

     {% extends 'app/layout/basic.html' %}
     {% load static %}
     {% block css %}
     	<link rel="stylesheet" href="{% static 'css/account.css' %}">
     {% endblock %}
     {% block content %}
     	<div class="account">
     		<div class="title"> 登录</div>
     		<form id="login_form" method="post">
     			{% csrf_token %}
     			<div class="form-group">
     				{% for field in fields %}
     					<div class="form-group">
     						<label for={{ field.id_for_label }}>{{ field.label }}</label>
     						{{ field }}
     						<span class="error-msg"></span>
     					</div>
     				{% endfor %}
     			</div>
     			<input id="btnSubmit" type="button" class="btn btn-primary btn-block " value="登录">
     		</form>
     	</div>
     {% endblock %}
     {% block js %}
     	<script>
     		$(document).ready(function () {
     			btnSubmitClick()
     		})
    
     		function btnSubmitClick() {
     			$("#btnSubmit").click(function () {
     				let data = $("#login_form").serialize();
     				$.ajax({
     					url: "{% url 'app:login' %}",
     					type: "POST",
     					data: data,
     					async: true,
     					dataType: "json",
     					success: function (res) {
     						if (res.status) {
     							location.href='/';
     						} else {
     							$.each(res.errors, function (key, value) {
     								$("#id_" + key).next().text(value);
     							})
     						}
     					},
     					errors: function () {
     						alert("请求失败");
     					}
     				})
    
     			})
     		}
     	</script>
     {% endblock %}
    

四、登录页面的路由。

  1. 登录页面的路由写在app-urls.py 文件中,代码如下:

     from django.urls import path
     from app.views.app.views import *
    
     urlpatterns = [
     	path('register/', register, name='register'),  # 注册的路由
     	path('login/', login_view, name='login'),  # 登录的路由
     ]
    

五、在导航栏上体现登录状态。

  1. 导航栏的登录状态与非登录状态对比如下面两张图:
    image
    image
  2. 代码在app-templates-app-layout-basic.html里编写。实现原理是,如果能获取请求网页的用户对象的用户名,则判断用户为登录状态,则在导航栏显示用户名和用户中心。如果不能获取请求用户对象的用户名,则判断用户为非登录状态,导航栏显示登录和注册链接。具体代码的位置如下图:
    image
  3. 具体的代码如下:
<ul class="nav navbar-nav navbar-right">
                {% if request.user.username %}
                    <li><a href="#">欢迎你:{{ request.user.username }}</a></li>
                    <li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
                           aria-expanded="false">用户中心 <span class="caret"></span></a>
                        <ul class="dropdown-menu">
                            <li><a href="#">Action</a></li>
                            <li><a href="#">Another action</a></li>
                            <li><a href="#">Something else here</a></li>
                            <li role="separator" class="divider"></li>
                            <li><a href="#">Separated link</a></li>
                        </ul>
                    </li>
                {% else %}
                    <li><a href="{% url 'app:login' %}">登录</a></li>
                    <li><a href="{% url 'app:register' %}">注册</a></li>
                {% endif %}
            </ul>

六、优化注册功能,实现注册完自动登录。

  1. 上一节的注册功能,只实现了用户注册信息写入数据库。在这里,我在注册视图里加如登录功能。具体的思路是:如果用户的注册的结果不为空,则使用auth组件的authenticate方法,验证用户注册时使用的用户名和密码,并返回用户对象。接下来,使用auth组件的login方法,进行用户登录。
  2. 需要优化代码的位置:代码在app-views-views.py 文件的register方法下。优化后的register方法的代码如下:
# 注册视图
def register(request):
    """
    1、如果是GET请求,向注册模板返回表单数据;
    2、如果是POST请求,执行注册动作;如果注册成功,新用户登录,向模板返回status的值是True。否则,返回status返回的值是False,并把错误信息返回给模板。
    """
    if request.method == 'GET':
        fields = RegisterForm()
        return render(request, 'app/register.html', {'fields': fields})
    if request.method == 'POST':
        data = request.POST
        fields = RegisterForm(data)
        if fields.is_valid():
            username = request.POST.get('username', '')
            password = request.POST.get('password', '')
            email = request.POST.get('email', '')
            phone_num = request.POST.get('phone_num', '')
            address = request.POST.get('address', '')
            # 注册
            reg_ok = MyUser.objects.create_user(username=username, password=password, email=email, phone_num=phone_num,
                                                address=address)
            # 如果注册成功,验证用户名密码,登录系统
            if reg_ok:
                # 验证用户名密码,获取验证后的用户对象
                user = authenticate(username=username, password=password)
                # 登录系统
                login(request=request,user=user)

            return JsonResponse({"status": True})
        else:
            return JsonResponse({"status": False, "errors": fields.errors})

posted @ 2024-01-05 10:05  喜气洋洋白云山  阅读(127)  评论(0编辑  收藏  举报