Django 小实例S1 简易学生选课管理系统 5 实现注册功能
Django 小实例S1 简易学生选课管理系统 第5节——实现注册功能
点击查看教程总目录
作者自我介绍:b站小UP主,时常直播编程+红警三,python1对1辅导老师。
本文涉及到的新的额外知识点:
Class-based views
没有这部分基础的读者,建议一边阅读本文一边查阅相关知识
这里推荐我的专栏:Django自学笔记 相关章节内容
1 添加注册页面模板(template)
在templates/user下新建register.html如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>
Register
</title>
</head>
<body>
<div class="register-container">
<div class="register-title">注册</div>
<form method="post" class="form">
{% csrf_token %}
{{form.as_p}}
<p><input type="submit" value="注册" class="submit-button"/></p>
</form>
</div>
</body>
2 添加对应的视图(view)方法
这里先思考,要完成注册功能,视图方法应该实现怎样的功能。
注册一个新的学生账号,就是在student数据库表中添加一个新的记录。
对应到Django项目,则是通过新建一个学生模型(model)实例。 (教师同理)
Django为 model 类实现了一些功能强大的视图类,使你能够快速完成一个为model进行增删查改等等操作的视图类,同时使用视图类的特定方法生成视图。
这样的视图类一般称为CBV(Class-based views)
在这里我们直接使用为model类进行新增实例的CreateView。
方便我们直接根据指定的字段生成前端表单,该生成的表单自带检查字段格式的功能,同时也方便我们在后端接受表单请求后按照表单数据生成对应的实例。
如果不使用CBV,上面介绍的繁琐的过程都需要我们手动一步一步实现,这是很痛苦麻烦低效的。
cbv本身只能够指定根据哪些字段生成对应的前端表单。
但我们这里需要实现一个略微复杂一点的功能: 注册页面除了需要填写密码还需要确认密码(即再填写一遍密码),同时提交时,需要先检查这两个是否一致。
要完成这个功能,我们需要实现一个定制化的表单
实现定制化的表单
在user/forms.py文件中,添加代码
class StuRegisterForm(forms.ModelForm):
confirm_password = forms.CharField(widget=forms.PasswordInput(), label="确认密码")
class Meta:
model = Student
fields = ('grade',
'name',
'password',
'confirm_password',
'gender',
'birthday',
'email',
'info')
def clean(self):
cleaned_data = super(StuRegisterForm, self).clean()
password = cleaned_data.get('password')
confirm_password = cleaned_data.get('confirm_password')
if confirm_password != password:
self.add_error('confirm_password', 'Password does not match.')
class TeaRegisterForm(forms.ModelForm):
confirm_password = forms.CharField(widget=forms.PasswordInput(), label="确认密码")
class Meta:
model = Teacher
fields = ('name',
'password',
'confirm_password',
'gender',
'birthday',
'email',
'info')
def clean(self):
cleaned_data = super(TeaRegisterForm, self).clean()
password = cleaned_data.get('password')
confirm_password = cleaned_data.get('confirm_password')
if confirm_password != password:
self.add_error('confirm_password', 'Password does not match.')
然后为学生和老师这两种model都添加下对应的视图类
实现CBV
新建user/cbvs.py如下
from django.shortcuts import reverse, redirect
from django.views.generic import CreateView
from user.forms import StuRegisterForm, TeaRegisterForm
from user.models import Student, Teacher
import random
class CreateStudentView(CreateView):
model = Student
form_class = StuRegisterForm
# fields = "__all__"
template_name = "user/register.html"
success_url = "login"
def form_valid(self, form):
# 学生注册时选定年级自动生成学号
grade = form.cleaned_data["grade"]
# order_by默认升序排列,number前的负号表示降序排列
student_set = Student.objects.filter(grade=grade).order_by("-number")
if student_set.count() > 0:
last_student = student_set[0]
new_number = str(int(last_student.number) + 1)
for i in range(6 - len(new_number)):
new_number = "0" + new_number
else:
new_number = "000001"
# Create, but don't save the new student instance.
new_student = form.save(commit=False)
# Modify the student
new_student.number = new_number
# Save the new instance.
new_student.save()
# Now, save the many-to-many data for the form.
form.save_m2m()
self.object = new_student
uid = grade + new_number
from_url = "register"
base_url = reverse(self.get_success_url(), kwargs={'kind': 'student'})
return redirect(base_url + '?uid=%s&from_url=%s' % (uid, from_url))
class CreateTeacherView(CreateView):
model = Teacher
form_class = TeaRegisterForm
template_name = "user/register.html"
success_url = "login"
def post(self, request, *args, **kwargs):
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
# 老师注册时随机生成院系号, 院系号范围为[0,300)
department_no = random.randint(0, 300)
# 把非三位数的院系号转换为以0填充的三位字符串,如1转换为'001'
department_no = '{:0>3}'.format(department_no)
teacher_set = Teacher.objects.filter(department_no=department_no).order_by("-number")
if teacher_set.count() > 0:
last_teacher = teacher_set[0]
new_number = int(last_teacher.number) + 1
new_number = '{:0>7}'.format(new_number)
else:
new_number = "0000001"
# Create, but don't save the new teacher instance.
new_teacher = form.save(commit=False)
# Modify the teacher
new_teacher.department_no = department_no
new_teacher.number = new_number
# Save the new instance.
new_teacher.save()
# Now, save the many-to-many data for the form.
form.save_m2m()
self.object = new_teacher
uid = department_no + new_number
from_url = "register"
base_url = reverse(self.get_success_url(), kwargs={'kind': 'teacher'})
return redirect(base_url + '?uid=%s&from_url=%s' % (uid, from_url))
这里介绍下上面的业务逻辑,在本项目S1的第三章第一节说过:
学生年级号为4位数字组成的字符串,年级下子学号为6位数字组成的字符串。
这两个连接起来组成学生的唯一学号,该学号也为其登录使用的账号。
比如学生李大爽,年级号为"2020",子学号为"000001",其学号为"2020000001"。
其中年级号是学生注册时自己选择的,子学号是注册时按照其年级内注册的先后顺序生成的。
同一年级,第一个注册的是"000001",第二个是"000002",依次类推。
这部分功能是在上面的CreateStudentView中的form_valid方法中实现的,该方法会返回一个HttpResponseRedirect对象,对应的效果是学生注册成功后,会返回到该重定向页面所指向的网页,这里对应的是注册详情页。
一般来说转么做一个注册成功页面会好些,不过这是个小项目,这里我就懒得去专门再搞个新页面了。
由于注册后的账号是后台生成的,注册者并不知道,所以重定向后需要将账号展示给注册者看。
这里采用的技术是通过url来传参,传到注册详情页展示给注册者看。
而对于老师
说明:老师院系号为3位数字组成的字符串,院内编号为7位数字组成的字符串。
这两个连接起来组成老师的唯一教师号,该教师号也为其登录使用的账号。
比如老师牛有力,院系号为"266",院内编号为"0000001",其教师号为"2660000001"。
其中院系号目前是随机生成的(最早是想做由院系模块,后来觉得工作量大就先放弃了,如果有人想做的话可以自行拓展)
院内编号是注册时按照其院内注册的先后顺序生成的。
同一院系,第一个注册的是"0000001",第二个是"0000002",依次类推。
这部分功能是在上面的CreateTeacherView中的form_valid方法中实现的,该方法会返回一个HttpResponseRedirect对象,对应的效果是老师注册成功后,会返回到该重定向页面所指向的网页,这里对应的是注册详情页。
实现注册视图方法
一般来说,实现CBV后,使用CBV自带的as_view()就可以生成需要的view方法了。
但是我们这里有些不同,由于有老师和学生两种注册,我想要用同一个视图方法来处理这两种请求。
那么视图方法
- 需要接收个参数,该参数需要标明是老师注册与学生注册中的哪一种
- 内部用条件判断语句,针对不同的种类,返回不同的视图结果
逻辑理清,在user/views.py中,继续添加代码如下
# 在开头导入视图类
from user.cbvs import CreateStudentView, CreateTeacherView
def register(request, kind):
func = None
if kind == "student":
func = CreateStudentView.as_view()
elif kind == "teacher":
func = CreateTeacherView.as_view()
if func:
return func(request)
else:
return HttpResponse(INVALID_KIND)
好了,到这里,注册部分的视图方法就算完成了
3 更新url
在user/urls.py文件中,
给urlpatterns列表添加一行元素:
path('register/<slug:kind>', views.register, name="register")
再修改下templates/user/login_detail.html,为注册功能添加对应的进入链接
即修改第17行,修改前应该是
<a href="">注册</a>
修改后为
<a href="{% url 'register' kind%}">注册</a>
4 展示注册后的账号信息
最后,修改下登录详情页部分代码,使其能够展示注册得到的账号信息,该信息是通过url来进行传参的。
更新user/views.py中的login方法如下
def login(request, *args, **kwargs):
if not kwargs or kwargs.get("kind", "") not in ["student", "teacher"]:
return HttpResponse(INVALID_KIND)
kind = kwargs["kind"]
context = {'kind': kind}
if request.method == 'POST':
if kind == "teacher":
form = TeaLoginForm(data=request.POST)
else:
form = StuLoginForm(data=request.POST)
if form.is_valid():
uid = form.cleaned_data["uid"]
temp_res = "hello, %s" % uid
return HttpResponse(temp_res)
else:
context['form'] = form
elif request.method == 'GET':
if request.GET.get('uid'):
uid = request.GET.get('uid')
context['uid'] = uid
data = {"uid":uid, 'password': '12345678'}
if kind == "teacher":
form = TeaLoginForm(data)
else:
form = StuLoginForm(data)
else:
if kind == "teacher":
form = TeaLoginForm()
else:
form = StuLoginForm()
context['form'] = form
if request.GET.get('from_url'):
context['from_url'] = request.GET.get('from_url')
return render(request, 'user/login_detail.html', context)
再更新templates/user/login_detail.html如下
{% extends "user/background.html" %}
{% block welcome_message %}
{% if from_url == "register" %}
<div class="welcome-message">注册成功,你的{% if kind == "student" %}学号{% else %}账号{% endif %}是 {{ uid }}</div>
{% else %}
<div class="welcome-message">欢迎</div>
{% endif %}
{% endblock %}
{% block login_container %}
{% if kind == "student" %}
<div class="login-kind-title">我是学生</div>
{% else %}
<div class="login-kind-title">我是老师</div>
{% endif %}
<div class = "form">
<form method="post">
{% csrf_token %}
{{form.as_p}}
<div class="submit-button">
<input type="submit" value="登录"/>
<a href="{% url 'register' kind%}">注册</a>
</div>
</form>
<div class="return-button"><a href="{% url 'login' %}">返回上一页</a></div>
</div>
{% endblock %}
然后运行项目,浏览器打开http://127.0.0.1:8000/user/register/student,效果如图

按如下图信息(其中密码为zhang333)

注册账号后,效果如下

5 后续优化之添加返回按钮
后续发现注册页面缺乏返回按钮,这里补充上。
在templates/user/register.html的表单下,即</form>之后添加
<div class="return-button">
<a href="{% url 'login' kind %}">返回上一页</a>
</div>
这时模板需要kind这个变量。我们需要在参数里面加上。
在user/cbvs.py中,分别给CreateStudentView类、CreateTeacherView类重写一下get_context_data方法,如下
### 在CreateStudentView类中重写:
def get_context_data(self, **kwargs):
context = super(CreateStudentView, self).get_context_data(**kwargs)
context["kind"] = "student"
return context
### 在CreateTeacherView类中重写:
def get_context_data(self, **kwargs):
context = super(CreateTeacherView, self).get_context_data(**kwargs)
context["kind"] = "teacher"
return context
Django 小实例S1 简易学生选课管理系统 5 实现注册功能的更多相关文章
- Django 小实例S1 简易学生选课管理系统 12 CSS样式完善
Django 小实例S1 简易学生选课管理系统 第12节--CSS样式完善 点击查看教程总目录 作者自我介绍:b站小UP主,时常直播编程+红警三,python1对1辅导老师. 课程模块的逻辑代码到这里 ...
- Django 小实例S1 简易学生选课管理系统 11 学生课程业务实现
Django 小实例S1 简易学生选课管理系统 第11节--学生课程业务实现 点击查看教程总目录 作者自我介绍:b站小UP主,时常直播编程+红警三,python1对1辅导老师. 课程模块中,学生需要拥 ...
- Django 小实例S1 简易学生选课管理系统 10 老师课程业务实现
Django 小实例S1 简易学生选课管理系统 第10节--老师课程业务实现 点击查看教程总目录 作者自我介绍:b站小UP主,时常直播编程+红警三,python1对1辅导老师. 课程模块中,老师将要使 ...
- Django 小实例S1 简易学生选课管理系统 9 创建课程模型(model)
Django 小实例S1 简易学生选课管理系统 第9节--创建课程模型(model) 点击查看教程总目录 作者自我介绍:b站小UP主,时常直播编程+红警三,python1对1辅导老师. 对于课程模块, ...
- Django 小实例S1 简易学生选课管理系统 8 CSS样式优化
Django 小实例S1 简易学生选课管理系统 第8节--CSS样式优化 点击查看教程总目录 作者自我介绍:b站小UP主,时常直播编程+红警三,python1对1辅导老师. 前面的几节下来,用户模块基 ...
- Django 小实例S1 简易学生选课管理系统 7 修改个人信息
Django 小实例S1 简易学生选课管理系统 第7节--修改个人信息 点击查看教程总目录 作者自我介绍:b站小UP主,时常直播编程+红警三,python1对1辅导老师. 用户模块除了注册登录之外,还 ...
- Django 小实例S1 简易学生选课管理系统 6 实现登录逻辑
Django 小实例S1 简易学生选课管理系统 第6节--实现登录逻辑 点击查看教程总目录 作者自我介绍:b站小UP主,时常直播编程+红警三,python1对1辅导老师. 1 业务逻辑 本教程第四节里 ...
- Django 小实例S1 简易学生选课管理系统 2 新建项目(project)并进行设置
Django 小实例S1 简易学生选课管理系统 第2节--新建项目(project)并进行设置 点击查看教程总目录 作者自我介绍:b站小UP主,时常直播编程+红警三,python1对1辅导老师. 0 ...
- Django 小实例S1 简易学生选课管理系统 3 创建用户模型(model)
Django 小实例S1 简易学生选课管理系统 第3节--创建用户模型(model) 点击查看教程总目录 作者自我介绍:b站小UP主,时常直播编程+红警三,python1对1辅导老师. 本文涉及到的新 ...
随机推荐
- CSS写一个圣诞树Chrome浏览器小插件
一时兴起,突然想写一个Chrome浏览器插件,不知道写啥,就写了一个圣诞树小插件.项目源码>> Chrome浏览器插件 Chrome浏览器插件最主要的是:index.html.manife ...
- 题解 51nod 1597 有限背包计数问题
题目传送门 题目大意 给出 \(n\),第 \(i\) 个数有 \(i\) 个,问凑出 \(n\) 的方案数. \(n\le 10^5\) 思路 呜呜呜,傻掉了... 首先想到根号分治,分别考虑 \( ...
- 洛谷4035 JSOI2008球形空间产生器 (列柿子+高斯消元)
题目链接 qwq 首先看到这个题,感觉就应该从列方程入手. 我们设给定的点的坐标矩阵是\(x\),然后球心坐标\(a_1,a_2....a_n\) 根据欧几里得距离公式,对于一个\(n维空间\)的第\ ...
- 多项式(polynomial)
多项式(polynomial) 题目大意: 给出一个 n 次多项式 \(f(x)=\sum_{i=0}^na_ix^i\) 对于\(k ≤ x ≤ k + l − 1\) 的\(l\) 个\(x\), ...
- Tomcat实现自定义类加载器
什么是类加载器? 这是官方给的定义 在 Java 虚拟机的实现中,初始类可以作为命令行参数提供. 或者,该实现可以提供一个初始类,该类设置一个类加载器,该类加载器依次加载应用程序. 初始类的其他选择也 ...
- httpclient 登录成功后返回的cookie值访问下一页面
HttpClient4.x可以自带维持会话功能,只要使用同一个HttpClient且未关闭连接,则可以使用相同会话来访问其他要求登录验证的服务(见TestLogin()方法中的"执行get请 ...
- FastAPI 学习之路(五十六)将token存放在redis
在之前的文章中,FastAPI 学习之路(二十九)使用(哈希)密码和 JWT Bearer 令牌的 OAuth2,FastAPI 学习之路(二十八)使用密码和 Bearer 的简单 OAuth2,Fa ...
- 2021.10.12考试总结[NOIP模拟75]
T1 如何优雅的送分 考虑式子的实际意义.\(2^{f_n}\)实际上就是枚举\(n\)质因子的子集.令\(k\)为这个子集中数的乘积,就可以将式子转化为枚举\(k\),计算\(k\)的贡献. 不难得 ...
- 热身训练4 Article
Article 在这个学期即将结束时,DRD开始写他的最后一篇文章. DRD使用著名的Macrohard的软件World来写他的文章. 不幸的是,这个软件相当不稳定,它总是崩溃. DRD需要在他的文章 ...
- 零基础学习STM32之入门学习路线
可以说就目前的市场需求来看,stm32在单片机领域已经拥有了绝对的地位,51什么的已经过时了也只能拿来打基础了,最后依然会转到stm32来,也正是因为这样stm32的学习者越来越多,其中不难发现绝大部 ...