用户数据表如下所示:
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
图形验证码的相关知识请看:【Django】图形验证码显示及验证
数据库操作的相关知识请看:【Django】Mysql数据库操作(增、删、改、查)
当用户以GET方式访问注册界面时,仅生成图形验证码并传到前端显示。
当用户以POST方式访问注册界面时,需要验证前端传入的邮箱、密码和图形验证码,这部分的内容都在register_post_form.is_valid()
这行代码中完成,系统会自动跳转到django内置的form表单验证模块进行验证,具体请看表单验证小节。最后,将数据写入MySQL数据库中并将表单数据发往前端模板层。
class RegisterView(View):
def get(self, request, *args, **kwargs):
register_get_form = RegisterGetForm()
return render(request, "register.html", {
"register_get_form": register_get_form,
})
def post(self, request, *args, **kwargs):
register_post_form = RegisterPostForm(request.POST)
if register_post_form.is_valid():
email = register_post_form.cleaned_data["email"]
password = register_post_form.cleaned_data["password"]
user = UserProfile(username=email, email=email)
user.set_password(password)
user.save()
login(request, user)
return HttpResponseRedirect(reverse("index"))
else:
register_get_form = RegisterGetForm()
return render(request, "register.html", {
"register_get_form": register_get_form,
"register_post_form": register_post_form,
})
注意:配置urls时需要设置
name
参数,后续前端界面配置url跳转时会使用到该参数。
from apps.users.views import RegisterView
urlpatterns += [
······
path('register/', RegisterView.as_view(), name="register"),
]
forms表单验证主要包括两部分:对前端表单数据的约束和对前端表单数据的验证。对数据的约束已经体现在变量定义中,数据验证则使用局部钩子对邮箱进行验证,保证邮箱唯一。对图形验证码captcha
的验证不需要我们进行编码,模块中已经内置。
Q:什么是form表单中的局部钩子?
A:定义一个函数,名字叫:clean_字段名字,内部,取出该字段,进行校验,如果通过,将该字段返回,如果失败,抛异常(ValidationError)
注意:forms组件中的变量名必须与前端输入框的标签保持一致。
class RegisterGetForm(forms.Form):
captcha = CaptchaField()
class RegisterPostForm(forms.Form):
captcha = CaptchaField()
email = forms.EmailField(required=True) # 变量名必须与前端name标签保持一致
password = forms.CharField(required=True, min_length=6)
def clean_email(self):
email = self.data.get("email")
users = UserProfile.objects.filter(email=email)
if users:
raise forms.ValidationError("该邮箱已注册")
return email
method="post"
;配置form表单向注册url提交数据:action="{% url 'register' %}"
,其中register是urls.py配置中所设置的name参数,对应url:http://127.0.0.1:8000/register/。{{ register_get_form.captcha }}
<form id="email_register_form" method="post" action="{% url 'register' %}" autocomplete="off">
<div class="form-group marb20 {% if register_post_form.errors.email %}errorput{% endif %}">
<label>邮 箱</label>
<input type="text" id="id_email" name="email" value="{{ register_post_form.email.value }}"
placeholder="请输入您的邮箱地址"/>
</div>
<div class="form-group marb8 {% if register_post_form.errors.password %}errorput{% endif %}">
<label>密 码</label>
<input type="password" id="id_password" name="password"
value="{{ register_post_form.password.value }}"
placeholder="请输入6-20位非中文字符密码"/>
</div>
<div class="form-group marb8 captcha1 ">
<label>验 证 码</label>
{{ register_get_form.captcha }}
</div>
<div class="error btns" id="jsEmailTips"></div>
{% if register_post_form.errors %}
{% for key, error in register_post_form.errors.items %}
{{ error }}
{% endfor %}
{% else %}
{{ msg }}
{% endif %}
<div class="auto-box marb8">
</div>
<input class="btn btn-green" id="jsEmailRegBtn" type="submit" value="注册并登录"/>
{% csrf_token %}
</form>