文章目录
- 1 模型层开发
- 2 视图层开发
- 3 form表单验证
- 4 配置urls.py
- 5 模板层开发
- 6 效果展示
1 模型层开发
用户数据表如下所示:
Field | Type | Extra |
---|---|---|
id | int | Prime Key & Auto Increment |
password | varchar(128) | |
last_login | datetime(6) | Allow Null |
is_superuser | tinyint(1) | |
username | varchar(150) | |
first_name | varchar(150) | |
last_name | varchar(150) | |
varchar(254) | ||
is_staff | tinyint(1) | |
is_active | tinyint(1) | |
date_joined | datetime(6) | |
nick_name | varchar(50) | |
birthday | date | Allow Null |
gender | varchar(6) | |
address | varchar(100) | |
mobile | varchar(11) | |
image | varchar(100) |
由于Django内置了用户数据表,因此并没有新建数据表,而是选择重写默认用户数据表。由于后续诸多数据表都会用到add_time
数据项,所以将该数据项暂时放在一个抽象类中,其他实体类继承于该抽象类。
这里提到的相关技术请参照:
【Django】模型层开发之重写模型类
【Django】模型层开发之创建并继承抽象模型类
from datetime import datetime
from django.db import models
from django.contrib.auth.models import AbstractUser
GENDER_CHOICES = (
("male", "男"),
("famale", "女"),
)
class BaseModel(models.Model):
"""
用于存放多个模型共用的数据列,且不生成该类的数据表
"""
add_time = models.DateTimeField(default=datetime.now, verbose_name="数据添加时间")
class Meta:
# 防止父类建表
abstract = True
class UserProfile(AbstractUser):
"""
重写用户模型类,继承自 AbstractUser
"""
nick_name = models.CharField(max_length=50, verbose_name="昵称", default="")
birthday = models.DateField(verbose_name="生日", null=True, blank=True)
gender = models.CharField(verbose_name="性别", choices=GENDER_CHOICES, max_length=6)
address = models.CharField(max_length=100, verbose_name="地址", default="")
# mobile = models.CharField(max_length=11, unique=True, verbose_name="电话号码")
mobile = models.CharField(max_length=11, verbose_name="电话号码")
image = models.ImageField(verbose_name="用户头像", upload_to="head_image/%Y%m", default="default.jpg")
class Meta:
"""
对当前表进行相关设置
"""
verbose_name = "用户信息"
verbose_name_plural = verbose_name
def __str__(self):
"""返回一个对象的描述信息"""
if self.nick_name:
return self.nick_name
else:
return self.username
2 视图层开发
整个视图层使用基于类的视图开发。
账号登录功能开发步骤如下:
- GET方式访问该URL时,使用django内置参数
is_authenticated
,判断用户是否已经登陆过(检查cookies),若已登录则跳转至首页,反之跳转到登录界面; - POST方式访问时,按照如下步骤进行:
-
使用django内置的form表单模块,验证数据是否有效,并获取表单数据,若数据无效则返回登陆页面;
-
若表单数据不为空则使用django内置
authenticate
函数判断用户是否存在于数据库中;这里之所以使用django内置
authenticate
函数,而不使用user.objects.filter(username=username)
的原因是:
- 若只检查用户名或密码并不能完全查询到该用户;
- 若同时验证用户名和密码,数据库中存储的密码为密文,用户输入的是明文,要经过一次加密才能验证,编码复杂; -
若查询到用户,则使用django内置的
login()
函数登录并使用HttpResponseRedirect()
函数重定向到index界面,否则使用render()
函数返回登陆页面,并回传错误信息和错误数据。
-
退出登录仅需要调用内置的logout()
函数并重定向到主页(index.html)即可。
from django.shortcuts import render
from django.views.generic.base import View
from django.contrib.auth import authenticate, login, logout
from django.http import HttpResponseRedirect
from django.urls import reverse
from apps.operations.models import UserProfile
from apps.users.forms import LoginForm, DynamicLoginForm, RegisterGetForm, RegisterPostForm
class LogoutView(View):
def get(self, request, *args, **kwargs):
logout(request)
return HttpResponseRedirect(reverse("index"))
class LoginView(View):
def get(self, request, *args, **kwargs):
if request.user.is_authenticated:
return HttpResponseRedirect(reverse("index"))
return render(request, "login.html")
def post(self, request, *args, **kwargs):
login_form = LoginForm(request.POST) # 创建表单用于验证数据以及获取数据
if login_form.is_valid():
user_name = login_form.cleaned_data["username"]
password = login_form.cleaned_data["password"]
# 表单验证
if not user_name:
return render(request, "login.html", {"msg": "请输入用户名"})
if not password:
return render(request, "login.html", {"msg": "请输入密码"})
# 用户查询(通过用户名和加密后的密码)
user = authenticate(username=user_name, password=password)
if user is not None:
login(request, user)
# 重定向url,调用reverse函数通过urlname来反向解析url
return HttpResponseRedirect(reverse("index"))
else:
return render(request, "login.html", {"msg": "用户名或密码错误", "login_form": login_form})
else:
return render(request, "login.html", {"login_form": login_form})
3 form表单验证
django中自带form表单验证模块,我们只需要在forms.py文件中规定表单字段,然后在视图层中创建该表单对象并使用模块内置的is_valid()
函数验证即可,验证中会若出现错误信息会放在form.errors
对象中。例如:password
小于6个字符,就会在form.errors.password
对应的信息中提示该错误,模板层开发中会使用该参数。更多高级操作会在后续的功能开发中使用到。
注意:变量名必须与前端输入框的<name>标签保持一致。
from django import forms
class LoginForm(forms.Form):
"""
实现表单验证功能
"""
username=forms.CharField(required=True, min_length=2)
password=forms.CharField(required=True, min_length=6)
4 配置urls.py
注意:配置urls时需要设置
name
参数,后续前端界面配置url跳转时会使用到该参数。
from apps.users.views import LoginView, LogoutView
urlpatterns = [
path('login/', LoginView.as_view(), name="login"), # 当前app的专属urls配置文件
path('logout/', LogoutView.as_view(), name="logout"),
]
5 模板层开发
- 配置form表单提交方式为POST:
method="post"
;配置form表单向登录url提交数据:action="{% url 'login' %}"
,login
是urls.py配置中所设置的name
参数,对应url:http://127.0.0.1:8000/login/
。 - 根据form表单验证中的报错信息高亮标注报错数据对应的输入框:在
<input>
标签的class
属性中添加{% if login_form.errors.username %}errorput{% endif %}
- 显示报错信息。若form表单验证出错则显示其报错信息,否则显示视图层中回传的其余报错信息。
<div class="fl form-box">
<h2>帐号登录</h2>
<form action="{% url 'login' %}" method="post" autocomplete="off">
<input type='hidden' name='csrfmiddlewaretoken' value='mymQDzHWl2REXIfPMg2mJaLqDfaS1sD5'/>
<div class="form-group marb20 {% if login_form.errors.username %}errorput{% endif %}">
<label>用 户 名</label>
<input name="username" id="account_l" type="text" placeholder="手机号/邮箱"
value="{{ login_form.username.value }}"/>
</div>
<div class="form-group marb8 {% if login_form.errors.password %}errorput{% endif %}">
<label>密 码</label>
<input name="password" id="password_l" type="password" placeholder="请输入您的密码"
value="{{ login_form.password.value }}"/>
</div>
<div class="error btns login-form-tips" id="jsLoginTips">
{% if login_form.errors %}
{% for key, error in login_form.errors.items %}
{{ error }}
{% endfor %}
{% else %}
{{ msg }}
{% endif %}
</div>
<div class="auto-box marb38">
<a class="fr" href="forgetpwd.html">忘记密码?</a>
</div>
<input class="btn btn-green" id="jsLoginBtn" type="submit" value="立即登录 > "/>
<input type='hidden' name='csrfmiddlewaretoken' value='5I2SlleZJOMUX9QbwYLUIAOshdrdpRcy'/>
{% csrf_token %}
</form>
<p class="form-p">没有慕学在线网帐号?<a href="register.html">[立即注册]</a></p>
</div>
至此登录和退出登录功能开发完成,记得修改主页(index.html)的登录跳转按键相关属性。