有了第9节,本节的工作就相对简单多了。这是因为模板文件中我们提前考虑了不同应用情况下的代码。这里我们仅仅需要重复第9节的步骤即可。
1 创建应用teacher
(base) xxx@xxx-virtual-machine:~/AuthDemo$ django-admin startapp teacher
(base) xxx@xxx-virtual-machine:~/AuthDemo$
1.1 在应用teacher的目录下创建文件和文件夹
- 新建模板目录templates、templatetags,
- 新建文件forms.py、urls.py
- 在模板目录templates下,创建与应用名同名的子目录
1.2 在settings.py中注册应用
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"basedata",
"users","student",
"teacher",
]
2 在teacher/models.py中定义老师模型Teacher
from django.db import models
# Create your models here.
from users.models import User
from basedata.models import Province, City, County, College, Major
# 老师信息模型(从表)与User(主表) 一对一
# 与College(主表) 多对一
# 与Major(主表) 多对一
# 与Province(主表) 多对一
# 与City(主表) 多对一
# 与County(主表) 多对一
class Teacher(models.Model):
name = models.CharField(max_length=20, null=False) # 姓名
office = models.CharField(max_length=50, null=False) # 办公地址
# 如果删除了User表中的信息,其关联的学生信息也会被删除
user = models.OneToOneField(User,on_delete=models.CASCADE) #User外键
college = models.ForeignKey(College,on_delete=models.CASCADE) # College外键
major = models.ForeignKey(Major,on_delete=models.CASCADE) # Major外键
province = models.ForeignKey(Province,on_delete=models.CASCADE)# Province外键
city = models.ForeignKey(City,on_delete=models.CASCADE) # City外键
county = models.ForeignKey(County,on_delete=models.CASCADE) # County外键
# 覆盖对象对外的字符串表现形式
def __str__(self):
return self.name
2.1 数据迁移
(base) xxx@xxx-virtual-machine:~/AuthDemo$ python manage.py makemigrations
Migrations for 'teacher':
teacher/migrations/0001_initial.py
- Create model Teacher
(base) xxx@xxx-virtual-machine:~/AuthDemo$ python manage.py migrate teacher
Operations to perform:
Apply all migrations: teacher
Running migrations:
Applying teacher.0001_initial... OK
(base) xxx@xxx-virtual-machine:~/AuthDemo$
3 在tecaher/forms.py中,定义表单
TecacherAddForm、TeacherUpdateForm两张表单一摸一样,只是字段名称不一样。这是因为这两张表单要用在同一个页面中。所以每个输入框的id不能一样。TeacherUpdateForm在每个字段名称后面加上了U,并且增加了一个字段passwordU,用于修改用户密码。
两张表单都综合了User模型、Teacher模型中的信息。详细代码如下:
from django import forms
class TeacherAddForm(forms.Form):
GENDER_TYPE = (
("1","男"),
("2","女")
)
picture = forms.fields.ImageField(
label='设置头像',
required=False,
)
name = forms.fields.CharField( #要填入Student、Teacher模型中的字段
label = '真实姓名',
required =True,
min_length = 2,
max_length = 20,
error_messages={
"required":"真实姓名不可以为空!",
"min_length":"真实姓名不能低于2位!",
"max_length":"真实姓名不能超过50位!"
}
)
gender = forms.ChoiceField(
label = '性别',
required = True,
choices = GENDER_TYPE,
)
age = forms.fields.IntegerField(
label = '年龄',
required=True,
min_value =10,
max_value =120,
error_messages={
"required":"年龄不可以为空!",
}
)
address = forms.fields.CharField(
label = '住址',
required=True,
max_length=100,
error_messages={
"required":"住址不可以为空!",
}
)
office = forms.fields.CharField(
label = '办公地址',
required=True,
max_length=50,
error_messages={
"required":"办公地址不可以为空!",
}
)
email = forms.fields.EmailField(
label = '电子邮件',
required=True,
error_messages={
"required":"电子邮件不可以为空!",
}
)
phone = forms.fields.CharField(
label = '电话',
required=True,
max_length=11,
error_messages={
"required":"电话不可以为空!",
}
)
card_id = forms.fields.CharField(
label = '身份证号码',
required = True,
max_length=18,
error_messages={
"required":"身份证号码不可以为空!",
}
)
college = forms.fields.ChoiceField( #要填入Student、Teacher模型中的字段
label = '所属学院',
)
major = forms.fields.ChoiceField( #要填入Student、Teacher模型中的字段
label = '专业',
)
province = forms.fields.ChoiceField( #要填入Student、Teacher模型中的字段
label = '省份',
)
city = forms.fields.ChoiceField( #要填入Student、Teacher模型中的字段
label = '地市',
)
county = forms.fields.ChoiceField( #要填入Student、Teacher模型中的字段
label = '县区',
)
username = forms.fields.CharField(
label = '用户名',
required=True,
min_length=3,
max_length=50,
error_messages={
"required":"用户名不可以为空!",
"min_length":"用户名不能低于3位!",
"max_length":"用户名不能超过50位!"
}
)
nickname = forms.fields.CharField(
label = '昵称',
max_length=50
)
'''password = forms.fields.CharField(
label = '密码',
required=True,
initial='123456',
widget=forms.PasswordInput(),
min_length=6,
max_length=50,
error_messages={
"required":"密码不可以空",
"min_length": "密码不能低于6位!",
"max_length": "密码不能超过50位!"
}
)'''
is_active = forms.fields.BooleanField(
label = '激活状态',
required=False,
)
is_superuser= forms.fields.BooleanField(
label = '是否是超级用户',
required=False,
)
class TeacherUpdateForm(forms.Form):
GENDER_TYPE = (
("1","男"),
("2","女")
)
pictureU = forms.fields.ImageField(
label='设置头像',
required=False,
)
nameU = forms.fields.CharField( #要填入Student、Teacher模型中的字段
label = '真实姓名',
required =True,
min_length = 2,
max_length = 50,
error_messages={
"required":"真实姓名不可以为空!",
"min_length":"真实姓名不能低于2位!",
"max_length":"真实姓名不能超过50位!"
}
)
genderU = forms.ChoiceField(
label = '性别',
required = True,
choices = GENDER_TYPE,
)
ageU = forms.fields.IntegerField(
label = '年龄',
required=True,
min_value =10,
max_value =120,
error_messages={
"required":"年龄不可以为空!",
}
)
addressU = forms.fields.CharField(
label = '住址',
required=True,
max_length=100,
error_messages={
"required":"住址不可以为空!",
}
)
officeU = forms.fields.CharField(
label = '办公地址',
required=True,
max_length=50,
error_messages={
"required":"办公地址不可以为空!",
}
)
emailU = forms.fields.EmailField(
label = '电子邮件',
required=True,
error_messages={
"required":"电子邮件不可以为空!",
}
)
phoneU = forms.fields.CharField(
label = '电话',
required=True,
max_length=11,
error_messages={
"required":"电话不可以为空!",
}
)
card_idU = forms.fields.CharField(
label = '身份证号码',
required = True,
max_length=18,
error_messages={
"required":"身份证号码不可以为空!",
}
)
collegeU = forms.fields.ChoiceField( #要填入Student、Teacher模型中的字段
label = '所属学院',
)
majorU = forms.fields.ChoiceField( #要填入Student、Teacher模型中的字段
label = '专业',
)
provinceU = forms.fields.ChoiceField( #要填入Student、Teacher模型中的字段
label = '省份',
)
cityU = forms.fields.ChoiceField( #要填入Student、Teacher模型中的字段
label = '地市',
)
countyU = forms.fields.ChoiceField( #要填入Student、Teacher模型中的字段
label = '县区',
)
usernameU = forms.fields.CharField(
label = '用户名',
required=True,
min_length=3,
max_length=50,
error_messages={
"required":"用户名不可以为空!",
"min_length":"用户名不能低于3位!",
"max_length":"用户名不能超过50位!"
}
)
nicknameU = forms.fields.CharField(
label = '昵称',
max_length=50
)
passwordU = forms.fields.CharField(
label = '密码',
required=True,
initial='123456',
widget=forms.PasswordInput(),
min_length=6,
max_length=50,
error_messages={
"required":"密码不可以空",
"min_length": "密码不能低于6位!",
"max_length": "密码不能超过50位!"
}
)
is_activeU = forms.fields.BooleanField(
label = '激活状态',
required=False,
)
is_superuserU= forms.fields.BooleanField(
label = '是否是超级用户',
required=False,
)
last_loginU = forms.DateTimeInput()
4 在teacher/views.py中定义视图函数query、add、update、delete
add()、update()函数存在添加,修改失败的问题;需要将信息传递到上述两个函数重定向到的query()函数中。详细说明在代码中有:
重定向传值是通过session来进行的。
详细代码如下:
from django.shortcuts import render,redirect
# Create your views here.
from teacher.forms import TeacherAddForm,TeacherUpdateForm
from teacher.models import Teacher
from basedata.models import Province,City,County,College,Major
from django.core.paginator import Paginator
from django.core import serializers
# 导入获取自定义User对象的方法
from django.contrib.auth import get_user_model
User = get_user_model() # 获取自定义User模型
##########################################
# User 、Teacher的操作 (一对一) #
##########################################
# 分页查询所有指向数据库操作的主页面teacher.html
def query(request,per_page='2',current_page='1'):
'''
功 能:分页函数。
若是查询所有,进行分页。若是模糊查询,不分页。
参 数: per_page: 每页记录数, 默认值是'2'.
current_page: 当前页, 默认值是'1', 即首页
request.POST[name]: 模糊查询的条件
返回值: 一个字典。字典中的key含义如下:
'error': 可能的错误信息。 string
'count': 查询结果总记录数。 int
'count_all': 数据表中总记录数。 int
若count == count_all,就是全部查询
'per_page': 每页记录数。 int
'num_pages': 页面总数。 int
'current_page': 当前页面数。 int
'page_bar_range': 分页栏显示的数字范围。list
'result': 若不是模糊查询, 当前页面数对应的结果。querySet
若是模糊查询,不分页。模糊查询的所有结果。querySet
'user_list': 'result'中逐条对应的User详情。JSON字符串。
'form': Teacher的新增表单
'formU': Teacher的修改表单
'name': 查询条件。供页面刷新时<input>显示最近一次输入值用
'''
# 初始化返回值为空的字典
context = {}
# 读取add函数设置的session,若没有,则为None
context['add_code'] = request.session.get('add_code')
context['add_message'] = request.session.get('add_message')
context['add_errorINFO'] = request.session.get('add_errorINFO')
# 读取update设置传过来的session
context['update_code'] = request.session.get('update_code')
context['update_message'] = request.session.get('update_message')
context['update_errorINFO'] = request.session.get('update_errorINFO')
#删除由add函数设置的session
if request.session.get('add_code') != None:
request.session.pop('add_code')
request.session.pop('add_message')
request.session.pop('add_errorINFO')
#删除由update函数设置的session
if request.session.get('update_code') != None:
request.session.pop('update_code')
request.session.pop('update_message')
request.session.pop('update_errorINFO')
#因为前端上传的值都是字符串,所以需要转换为整数
per_page=int(per_page)
current_page=int(current_page)
# 获取数据,按id排序
varList = ''
if request.POST : # 模糊查询
varList = Teacher.objects.filter(name__contains = request.POST['search_name']).order_by('id')
# 保存查询条件,供index.html页面要设置搜索栏表单中的相应输入框value属性用
context['search_name'] = request.POST['search_name']
else: # 查询所有
context['search_name'] = ''
varList = Teacher.objects.all().order_by('id')
if varList.exists() : # 判断查询集中是否有数据
error = ''
else:
error = "表中没有数据 !"
# 创建分页器实例
paginator = Paginator(varList,per_page)
page = paginator.get_page(current_page)
# 设置在前端分页器栏为Bootstrap分页器内固定显示7页的参数
page_bar_range = range(1,8)
if paginator.num_pages > 7:
if current_page-3 < 1:
#当页面输入前三页时,使其分页器只显示前7页不变
page_bar_range = range(1,8)
elif current_page+3 > paginator.num_pages:
#当页面处于最后三页时,使分页器只显示最后固定7页
page_bar_range = range(paginator.num_pages-6,paginator.num_pages+1)
else:
page_bar_range = range(current_page-3,current_page+4)
else:
page_bar_range = paginator.page_range
context['page_bar_range'] = page_bar_range
context['count'] = paginator.count
context['count_all'] = Teacher.objects.all().count();
context['per_page'] = per_page
context['current_page'] = current_page
context['num_pages'] = paginator.num_pages
context['error'] = error
# 如果不是模糊查询,则分页;如果是,则不分页
if context['count'] == context['count_all']:
context['result'] = page
else:
context['result'] = varList
'''
通过Teacher(从表)正向查询的User(主表)
一对一关系:
只有从表的单个实例,才能通过 从表模型对象实例.外键名 进行跨表正向查询
context['result']是一个QuerySet,不能通过上述方法反查,所以需要逐条反查。
'''
userList=[]
for var in context['result']:
userList.append( var.user) # user为从表名的外键
'''
转换为JSON格式的字符串, 是因为需要在前端JS中处理这个数据。
'''
context['user_list'] = serializers.serialize("json",userList)
#print( context['user_list']) #在控制台显示转换后的JSON字符串
'''
将所有有关修改、新增所需要的基础数据列表传入前端
供前端<select>的<option>选项使用
'''
context['provinceList'] = querySetToList(Province.objects.all().order_by('id').values('id','name'))
context['cityList'] = querySetToList(City.objects.all().order_by('id').values('id','name','province_id'))
context['countyList'] = querySetToList(County.objects.all().order_by('id').values('id','name','city_id'))
context['collegeList'] = querySetToList(College.objects.all().order_by('id').values('id','name'))
context['majorList'] = querySetToList(Major.objects.all().order_by('id').values('id','name','college_id'))
context['form'] = TeacherAddForm() #修改和新增用户用到的空表格
#print(context['form'])
context['formU'] = TeacherUpdateForm() #修改和新增用户用到的空表格
return render(request, "teacher.html", context)
def querySetToList(querySet):
'''将querySet对象,转化为列表对象'''
varList =[]
for var in querySet:
varList.append( var)
return varList
import os
from django.conf import settings
def add(request):
# 初始化返回信息
# 因为add返回的是重定向到query
# 而新增过程中会出错,所以需要向query传递信息
# 只能通过session来query传递信息
request.session['add_code'] = 400
request.session['add_message'] = '用户注册失败'
request.session['add_errorINFO'] = ''
# 1 获取数据
name = request.POST["name"]
username = request.POST["username"]
#password = request.POST["password"]
email = request.POST["email"]
nickname = request.POST["nickname"]
gender = request.POST["gender"]
age = request.POST["age"]
phone = request.POST["phone"]
card_id =request.POST["card_id"]
address =request.POST["address"]
office =request.POST["office"]
#picture =request.POST["picture"]
if (request.POST.get('is_active') == 'on'):
is_active = True
else:
is_active = False
if (request.POST.get('is_superuser') == 'on'):
is_superuser = True
else:
is_superuser = False
college = request.POST["college"]
major = request.POST["major"]
province = request.POST["province"]
city = request.POST["city"]
county = request.POST["county"]
username_exists = User.objects.filter(username=username).exists()
# 如果用户名已经存在
if username_exists:
request.session['add_errorINFO'] = "您输入的用户名已存在!"
print("您输入的用户名已存在!")
return redirect("/teacher/query")
# 如果邮箱名已经存在
email_exists = User.objects.filter(email=email).exists()
if email_exists:
request.session['add_errorINFO'] = "您输入的邮箱已存在!"
print("您输入的邮箱名已存在!")
return redirect("/teacher/query")
# 如果电话号码已经存在
phone_exists = User.objects.filter(phone=phone).exists()
if phone_exists:
request.session['add_errorINFO'] = "您输入的电话号码已存在!"
print("您输入的电话号码已存在!")
return redirect("/teacher/query")
# 如果份证号码已经存在
card_id_exists = User.objects.filter(card_id=card_id).exists()
if card_id_exists:
request.session['add_errorINFO'] = "您输入的身份证号码已存在!"
print("您输入的身份证号码已存在!")
return redirect("/teacher/query")
#注册通过,返回页面
print("注册通过")
print(request.POST.get('picture'))
# 如果前端未选择头像文件,request.POST['picture']不存在
# 所以需要 request.POST.get('picture')来判断
if request.POST.get('picture') != '': # 如果不为空,则上传图像
# 处理图像上传
# 获取一个文件管理器对象
file = request.FILES['picture']
# 获取图像文件后缀
suffix = os.path.splitext(file.name)[-1]
# 保存文件名为用户名+后缀
save_file_name = username + suffix
# 头像文件的地址和文件名称
'''
static 是settings.py中定义的别名,指向静态目录statics
images 是 静态目录statics下的子目录
user_pictures 是 用来保存用户头像的子目录
'''
where = '/static/images/user_pictures/'+ save_file_name
# 分块保存image
content = file.chunks()
with open(where, 'wb') as f:
for i in content:
f.write(i)
else: # 如果为空,则采用默认图像
where = '/static/images/user_pictures/'+ 'default.jpg'
# 创建主表User
User.objects.create_user(
username=username,
password='123456', #初始密码为123456
email=email,
nickname = nickname,
gender =gender,
age =age,
phone =phone,
card_id =card_id,
address =address,
#picture=picture,
picture = where, #将上传文件的保存路径、文件名存入数据库
is_active =is_active,
is_staff = True,
is_superuser =is_superuser
)
request.session['add_code'] = 200
request.session['add_message'] = '注册通过'
# 创建从表Teacher
user_id = User.objects.get(email = email).id
Teacher(
name = name,
office =office,
user_id = user_id,
college_id =college,
major_id = major,
province_id =province,
city_id =city,
county_id = county,
).save()
return redirect("/teacher/query")
def update(request):
# 初始化返回信息
# 因为update返回的是重定向到query
# 而新增过程中会出错,所以需要向query传递信息
# 只能通过session来query传递信息
request.session['update_code'] = 400
request.session['update_message'] = '用户修改失败'
request.session['update_errorINFO'] = ''
# 1 获取数据
print(request.POST)
id = request.POST['id']
user_id =request.POST['user_id']
name = request.POST["nameU"]
username = request.POST["usernameU"]
password = request.POST["passwordU"]
email = request.POST["emailU"]
nickname = request.POST["nicknameU"]
gender = request.POST["genderU"]
age = request.POST["ageU"]
phone = request.POST["phoneU"]
card_id =request.POST["card_idU"]
address =request.POST["addressU"]
office =request.POST["officeU"]
if (request.POST.get('is_activeU') == 'on'):
is_active = True
else:
is_active = False
if (request.POST.get('is_superuserU') == 'on'):
is_superuser = True
else:
is_superuser = False
college = request.POST["collegeU"]
major = request.POST["majorU"]
province = request.POST["provinceU"]
city = request.POST["cityU"]
county = request.POST["countyU"]
# 根据user_id 查询 修改前的User信息
userBeforUpdate = User.objects.get(id = user_id)
print(userBeforUpdate)
username_exists = User.objects.filter(username=username).exists()
# 如果用户名已经存在,并且与修改前的不一致
if (username_exists) and (username !=userBeforUpdate.username ):
request.session['update_errorINFO'] = "您输入的用户名已存在!"
print("您输入的用户名已存在!")
return redirect("/teacher/query")
# 如果邮箱名已经存在,并且与修改前的不一致
email_exists = User.objects.filter(email=email).exists()
if (email_exists) and (email !=userBeforUpdate.email ):
request.session['update_errorINFO'] = "您输入的邮箱已存在!"
print("您输入的邮箱名已存在!")
return redirect("/teacher/query")
# 如果电话号码已经存在,并且与修改前的不一致
phone_exists = User.objects.filter(phone=phone).exists()
if (phone_exists) and (phone !=userBeforUpdate.phone ):
request.session['update_errorINFO'] = "您输入的电话号码已存在!"
print("您输入的电话号码已存在!")
return redirect("/teacher/query")
# 如果身份证号码已经存在,并且与修改前的不一致
card_id_exists = User.objects.filter(card_id=card_id).exists()
if (card_id_exists) and (card_id != userBeforUpdate.card_id ):
request.session['update_errorINFO'] = "您输入的身份证号码已存在!"
print("您输入的身份证号码已存在!")
return redirect("/teacher/query")
#验证通过
print("验证通过")
print(request.POST.get('picture'))
# 如果前端未选择头像文件,request.POST['picture']不存在
# 所以需要 request.POST.get('picture')来判断
if request.POST.get('pictureU') != '': # 如果不为空,则上传图像
# 处理图像上传
# 获取一个文件管理器对象
file = request.FILES['pictureU']
# 获取图像文件后缀
suffix = os.path.splitext(file.name)[-1]
# 保存文件名为用户名+后缀
save_file_name = username + suffix
# 头像文件的地址和文件名称
'''
static 是settings.py中定义的别名,指向静态目录statics
images 是 静态目录statics下的子目录
user_pictures 是 用来保存用户头像的子目录
'''
where = '/static/images/user_pictures/'+ save_file_name
# 分块保存image
content = file.chunks()
with open(where, 'wb') as f:
for i in content:
f.write(i)
else: # 如果为空,则采用以前的图像
where = userBeforUpdate.picture
# 修改主表User
User.objects.filter(id= user_id).update(
username=username,
password=password,
email=email,
nickname = nickname,
gender =gender,
age =age,
phone =phone,
card_id =card_id,
address =address,
#picture=picture,
picture = where, #将上传文件的保存路径、文件名存入数据库
is_active =is_active,
is_staff = True,
is_superuser =is_superuser
)
request.session['update_code'] = 200
request.session['update_message'] = '修改完成'
# 修改从表Teacher
Teacher.objects.filter(id=id).update(
name = name,
office = office,
user_id = user_id,
college_id =college,
major_id = major,
province_id =province,
city_id =city,
county_id = county,
)
return redirect("/teacher/query")
def delete(request):
# 删除所选择的记录
# 将前端传过来的idList字符串分割为数组
idList=request.POST['idList'].split(' ')
user_idList=request.POST['user_idList'].split(' ')
print(idList)
print(user_idList)
for var in idList: # 删除从表
Teacher.objects.filter(id=int(var)).delete()
for var in user_idList: #删除主表,也可以直接删除主表就级联删除从表
User.objects.filter(id=int(var)).delete()
return redirect("/teacher/query")
from django.shortcuts import render,redirect
# Create your views here.
from teacher.forms import TeacherAddForm,TeacherUpdateForm
from teacher.models import Teacher
from basedata.models import Province,City,County,College,Major
from django.core.paginator import Paginator
from django.core import serializers
# 导入获取自定义User对象的方法
from django.contrib.auth import get_user_model
User = get_user_model() # 获取自定义User模型
##########################################
# User 、Teacher的操作 (一对一) #
##########################################
# 分页查询所有指向数据库操作的主页面teacher.html
def query(request,per_page='2',current_page='1'):
'''
功 能:分页函数。
若是查询所有,进行分页。若是模糊查询,不分页。
参 数: per_page: 每页记录数, 默认值是'2'.
current_page: 当前页, 默认值是'1', 即首页
request.POST[name]: 模糊查询的条件
返回值: 一个字典。字典中的key含义如下:
'count': 查询结果总记录数。 int
'count_all': 数据表中总记录数。 int
若count == count_all,就是全部查询
'per_page': 每页记录数。 int
'num_pages': 页面总数。 int
'current_page': 当前页面数。 int
'page_bar_range':分页栏显示的数字范围。list
'result': 若不是模糊查询, 当前页面数对应的结果。querySet
若是模糊查询,不分页,模糊查询的所有结果。querySet
'user_list': 和result对应的, 与Teacher模型一对一关系的User模型
'provinceList': 省份的列表。模型Province
'cityList': 地市的列表。模型City,与Province是多对一的关系
'countyList': 县区的列表。模型County,与City是多对一的关系
'collegeList': 学院的列表。模型College
'majorList': 专业列表。 模型Major,与College是多对一的关系
'form': Teacher的新增表单(包含Teacher、User的全部信息)
'formU': Teacher的修改表单(包含Teacher、User的全部信息)
'search_name': 查询条件。供页面刷新时<input>显示最近一次输入值用
'app_name': 应用名称。
'id': 页面选择状态
'code': add()、update()函数的状态码
'message': add()、update()函数的信息
'errorInfo': add()、update()函数的错误原因
'''
# 初始化返回值为空的字典
context = {}
# 初始化返回值为空的字典
context = {}
# 读取add()、update()函数设置的session,若没有,则为None
context['code'] = request.session.get('code')
context['message'] = request.session.get('message')
context['errorINFO'] = request.session.get('errorINFO')
#删除由add()、update()函数设置的session
if request.session.get('code') != None:
request.session.pop('code')
request.session.pop('message')
request.session.pop('errorINFO')
# 读取update()函数设置的页面,若没有,则为None
id ='0' #应为路由不传id值,所以设置一个
if request.session.get('per_page') != None:
# 读取session
per_page = int(request.session['per_page'])
current_page = int(request.session['current_page'])
id = int(request.session['id'])
#删除session
request.session.pop('per_page')
request.session.pop('current_page')
request.session.pop('id')
else: #没有session,则是路由传值,或初始值
#因为路由传值、初始值都是字符串,所以需要转换为整数
per_page = int(per_page)
current_page = int(current_page)
id = int(id)
# 获取数据,按id排序
varList = ''
if request.POST : # 模糊查询
varList = Teacher.objects.filter(name__contains = request.POST['search_name']).order_by('id')
# 保存查询条件,供index.html页面要设置搜索栏表单中的相应输入框value属性用
context['search_name'] = request.POST['search_name']
else: # 查询所有
context['search_name'] = ''
varList = Teacher.objects.all().order_by('id')
# 创建分页器实例
paginator = Paginator(varList,per_page)
page = paginator.get_page(current_page)
# 设置在前端分页器栏为Bootstrap分页器内固定显示7页的参数
page_bar_range = range(1,8)
if paginator.num_pages > 7:
if current_page-3 < 1:
#当页面输入前三页时,使其分页器只显示前7页不变
page_bar_range = range(1,8)
elif current_page+3 > paginator.num_pages:
#当页面处于最后三页时,使分页器只显示最后固定7页
page_bar_range = range(paginator.num_pages-6,paginator.num_pages+1)
else:
page_bar_range = range(current_page-3,current_page+4)
else:
page_bar_range = paginator.page_range
context['page_bar_range'] = page_bar_range
context['count'] = paginator.count
context['count_all'] = Teacher.objects.all().count();
context['per_page'] = per_page
context['current_page'] = current_page
context['num_pages'] = paginator.num_pages
context['id'] = id
# 如果不是模糊查询,则分页;如果是,则不分页
if context['count'] == context['count_all']:
context['result'] = page
else:
context['result'] = varList
'''
通过Teacher(从表)正向查询的User(主表)
一对一关系:
只有从表的单个实例,才能通过 从表模型对象实例.外键名 进行跨表正向查询
context['result']是一个QuerySet,不能通过上述方法反查,所以需要逐条反查。
'''
userList=[]
for var in context['result']:
userList.append( var.user) # user为从表名的外键
'''
转换为JSON格式的字符串, 是因为需要在前端JS中处理这个数据。
'''
context['user_list'] = serializers.serialize("json",userList)
#print( context['user_list']) #在控制台显示转换后的JSON字符串
'''
将所有有关修改、新增所需要的基础数据列表传入前端
供前端<select>的<option>选项使用
'''
context['provinceList'] = querySetToList(Province.objects.all().order_by('id').values('id','name'))
context['cityList'] = querySetToList(City.objects.all().order_by('id').values('id','name','province_id'))
context['countyList'] = querySetToList(County.objects.all().order_by('id').values('id','name','city_id'))
context['collegeList'] = querySetToList(College.objects.all().order_by('id').values('id','name'))
context['majorList'] = querySetToList(Major.objects.all().order_by('id').values('id','name','college_id'))
context['form'] = TeacherAddForm() #修改和新增用户用到的空表格
context['formU'] = TeacherUpdateForm() #修改和新增用户用到的空表格
context['app_name'] ='teacher'
return render(request, "index.html", context)
def querySetToList(querySet):
'''将querySet对象,转化为列表对象'''
varList =[]
for var in querySet:
varList.append( var)
return varList
import os
from django.conf import settings
def add(request):
# 初始化返回信息
# 因为add返回的是重定向到query
# 而新增过程中会出错,所以需要向query传递信息
# 只能通过session来query传递信息
request.session['code'] = 400
request.session['message'] = '用户注册失败'
request.session['errorINFO'] = ''
# 1 获取数据
name = request.POST["name"]
username = request.POST["username"]
email = request.POST["email"]
nickname = request.POST["nickname"]
gender = request.POST["gender"]
age = request.POST["age"]
phone = request.POST["phone"]
card_id = request.POST["card_id"]
address = request.POST["address"]
office = request.POST["office"]
if (request.POST.get('is_superuser') == 'on'):
is_superuser = True
else:
is_superuser = False
college = request.POST["college"]
major = request.POST["major"]
province = request.POST["province"]
city = request.POST["city"]
county = request.POST["county"]
# 2 判断用户名是否已经存在
username_exists = User.objects.filter(username=username).exists()
if username_exists: # 如果用户名已经存在
request.session['errorINFO'] = "您输入的用户名已存在!"
return redirect("/teacher/query")
# 3 判断邮箱名是否已经存在
email_exists = User.objects.filter(email=email).exists()
if email_exists: # 如果邮箱名已经存在
request.session['errorINFO'] = "您输入的邮箱已存在!"
return redirect("/teacher/query")
# 4 判断电话号码是否已经存在
phone_exists = User.objects.filter(phone=phone).exists()
if phone_exists: # 如果电话号码已经存在
request.session['errorINFO'] = "您输入的电话号码已存在!"
return redirect("/teacher/query")
# 5 判断身份证号码是否已经存在
card_id_exists = User.objects.filter(card_id=card_id).exists()
if card_id_exists: # 如果份证号码已经存在
request.session['errorINFO'] = "您输入的身份证号码已存在!"
return redirect("/teacher/query")
# 6 判断前端是否选择头像文件
# 如果前端未选择头像文件,request.POST['picture']不存在
# 所以需要 request.POST.get('picture')来判断
if request.POST.get('picture') != '': # 如果不为空,则上传图像
# 处理图像上传
# 获取一个文件管理器对象
file = request.FILES['picture']
# 获取图像文件后缀
suffix = os.path.splitext(file.name)[-1]
# 保存文件名为用户名+后缀
save_file_name = username + suffix
# 头像文件的地址和文件名称
'''
static 是settings.py中定义的别名,指向静态目录statics
images 是 静态目录statics下的子目录
user_pictures 是 用来保存用户头像的子目录
'''
where = '/static/images/user_pictures/'+ save_file_name
# 分块保存image
content = file.chunks()
with open(where, 'wb') as f:
for i in content:
f.write(i)
else: # 如果为空,则采用默认图像
where = '/static/images/user_pictures/'+ 'default.jpg'
# 7 创建主表User
User.objects.create_user(
username=username,
password = '123456', #初始密码为123456
email = email,
nickname = nickname,
gender = gender,
age = age,
phone = phone,
card_id = card_id,
address = address,
picture = where, #将上传文件的保存路径、文件名存入数据库
is_active = True,
is_staff = False,
is_superuser =is_superuser
)
# 8 创建从表Teacher
user_id = User.objects.get(email = email).id
Teacher(
name = name,
office =office,
user_id = user_id,
college_id =college,
major_id = major,
province_id =province,
city_id =city,
county_id = county,
).save()
# 9 设置session
# 操作状态
request.session['code'] = 200
request.session['message'] = '注册通过'
return redirect("/teacher/query")
def update(request):
# 初始化返回信息
# 因为update返回的是重定向到query
# 而新增过程中会出错,所以需要向query传递信息
# 只能通过session来query传递信息
request.session['code'] = 400
request.session['message'] = '用户修改失败'
request.session['errorINFO'] = ''
# 1 获取数据
print(request.POST)
id = request.POST['id']
user_id =request.POST['user_id']
current_page = request.POST["current_page"]
per_page = request.POST["per_page"]
name = request.POST["nameU"]
username = request.POST["usernameU"]
password = request.POST["passwordU"]
email = request.POST["emailU"]
nickname = request.POST["nicknameU"]
gender = request.POST["genderU"]
age = request.POST["ageU"]
phone = request.POST["phoneU"]
card_id =request.POST["card_idU"]
address =request.POST["addressU"]
office =request.POST["officeU"]
if (request.POST.get('is_activeU') == 'on'):
is_active = True
else:
is_active = False
if (request.POST.get('is_superuserU') == 'on'):
is_superuser = True
else:
is_superuser = False
college = request.POST["collegeU"]
major = request.POST["majorU"]
province = request.POST["provinceU"]
city = request.POST["cityU"]
county = request.POST["countyU"]
# 2 根据user_id 查询 修改前的User信息
userBeforUpdate = User.objects.get(id = user_id)
# 3 判断用户名是否已经存在
username_exists = User.objects.filter(username=username).exists()
if (username_exists) and (username !=userBeforUpdate.username ):# 如果用户名已经存在,并且与修改前的不一致
request.session['errorINFO'] = "您输入的用户名已存在!"
return redirect("/teacher/query")
# 4 判断邮箱名是否已经存在
email_exists = User.objects.filter(email=email).exists()
if (email_exists) and (email !=userBeforUpdate.email ):# 如果邮箱名已经存在,并且与修改前的不一致
request.session['errorINFO'] = "您输入的邮箱已存在!"
return redirect("/teacher/query")
# 5 判断电话号码是否已经存在
phone_exists = User.objects.filter(phone=phone).exists()
if (phone_exists) and (phone !=userBeforUpdate.phone ):# 如果电话号码已经存在,并且与修改前的不一致
request.session['errorINFO'] = "您输入的电话号码已存在!"
return redirect("/teacher/query")
# 6 判断身份证号码是否已经存在
card_id_exists = User.objects.filter(card_id=card_id).exists()
if (card_id_exists) and (card_id != userBeforUpdate.card_id ):# 如果身份证号码已经存在,并且与修改前的不一致
request.session['errorINFO'] = "您输入的身份证号码已存在!"
print("您输入的身份证号码已存在!")
return redirect("/teacher/query")
# 7 判断前端是否选择头像文件
# 如果前端未选择头像文件,request.POST['picture']不存在
# 所以需要 request.POST.get('picture')来判断
if request.POST.get('pictureU') != '': # 如果不为空,则上传图像
# 处理图像上传
# 获取一个文件管理器对象
file = request.FILES['pictureU']
# 获取图像文件后缀
suffix = os.path.splitext(file.name)[-1]
# 保存文件名为用户名+后缀
save_file_name = username + suffix
# 头像文件的地址和文件名称
'''
static 是settings.py中定义的别名,指向静态目录statics
images 是 静态目录statics下的子目录
user_pictures 是 用来保存用户头像的子目录
'''
where = '/static/images/user_pictures/'+ save_file_name
# 分块保存image
content = file.chunks()
with open(where, 'wb') as f:
for i in content:
f.write(i)
else: # 如果为空,则采用以前的图像
where = userBeforUpdate.picture
# 8 修改主表User
User.objects.filter(id= user_id).update(
username=username,
password=password,
email=email,
nickname = nickname,
gender =gender,
age =age,
phone =phone,
card_id =card_id,
address =address,
#picture=picture,
picture = where, #将上传文件的保存路径、文件名存入数据库
is_active =is_active,
is_staff = True,
is_superuser =is_superuser
)
# 9 修改从表Teacher
Teacher.objects.filter(id=id).update(
name = name,
office = office,
user_id = user_id,
college_id =college,
major_id = major,
province_id =province,
city_id =city,
county_id = county,
)
# 10 设置session
# 操作状态
request.session['code'] = 200
request.session['message'] = '用户组修改成功'
# 页面状态
request.session['current_page'] = current_page
request.session['per_page'] = per_page
request.session['id'] = id
return redirect("/teacher/query")
def delete(request):
# 删除所选择的记录
# 将前端传过来的idList字符串分割为数组
idList=request.POST['idList'].split(' ')
user_idList=request.POST['user_idList'].split(' ')
print(idList)
print(user_idList)
for var in idList: # 删除从表
Teacher.objects.filter(id=int(var)).delete()
for var in user_idList: #删除主表,也可以直接删除主表就级联删除从表
User.objects.filter(id=int(var)).delete()
return redirect("/teacher/query")
5 模板文件
除了teacher/module_query.html之外,其他的都可以第9节的模板文件。
<!-- module_query.html 在应用teacher目录下的模板目录templates中的teacher子目录中
内 容:以<table>展示查询和模糊查询的结果。
在<table>第一列设置复选框,用于同时选择多条记录,共批量删除用。
在<table>最后一列为操作列。设置两个默认禁用图标按钮用于当前行的修改、删除。
涉及的变量:
{{result}}: 含有多条查询结果。
每一行的key和数据表中的字段名相同。若{{var}}是{{result}}的一行数据,
那么各列数据分别为:{{var.id}}、{{var.name}}、{{var.office}}、
{{var.college}}、{{var.major}}、{{var.province}}、
{{var.city}}、{{var.county}}、{{var.user_id}}
-->
<table id='table' class="table table-striped text-info">
<thead>
<tr>
<td><input id="allChecked" type="checkbox"></td>
<th><h4>ID</h4></th>
<th><h4>姓名</h4></th>
<th><h4>办公地址</h4></th>
<th><h4>学院</h4></th>
<th><h4>专业</h4></th>
<th><h4>省份</h4></th>
<th><h4>地市</h4></th>
<th><h4>县</h4></th>
<th><h4>User</h4></th>
<th><h4>操作</h4></th>
</tr>
</thead>
<tbody>
{% for var in result %}
<tr>
<td><input class="checked" type="checkbox"></td>
<td class="id"> <h5>{{var.id}}</h5></td>
<td> <h5>{{var.name}}</h5></td>
<td> <h5>{{var.office}}</h5></td>
<td class="college"> <h5>{{var.college}}</h5></td>
<td class="major"> <h5>{{var.major}}</h5></td>
<td class="province"> <h5>{{var.province}}</h5></td>
<td class="city"> <h5>{{var.city}}</h5></td>
<td class="county"> <h5>{{var.county}}</h5></td>
<td class="user_id"> <h5>{{var.user_id}}</h5></td>
<td class="edit">
<!--修改按钮 启用id为module_updateModal的弹窗-->
<button type="button" class="update" data-toggle="modal" data-target="#module_updateModal" disabled="disabled">
<i class="fa-regular fa-pen-to-square"></i>
</button>
<!--删除按钮 启用id为module_deleteModal的弹窗-->
<button type="button" class="delete" data-toggle="modal" data-target="#module_deleteModal" disabled="disabled">
<i class="fa-solid fa-trash-can"></i>
</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
6 在teacher/urls.py中定义子路由
from django.urls import path,re_path
from . import views as view
# 子路由列表
urlpatterns = [
path('query/', view.query, name='query-url'), # 分页查询
re_path(r'^query/(?P<per_page>\d+)/(?P<current_page>\d+)/$',view.query), #传值路由
path('add/', view.add, name='add-url'), # 新增
path('update/',view.update, name='update-url'), # 修改
path('delete/',view.delete, name='delete-url'), # 删除
]
7 在AuthDemo/urls.py中管理子路由
from django.contrib import admin
from django.urls import path,includeurlpatterns = [
path("admin/", admin.site.urls),
path('basedata/',include(('basedata.urls','basedata'))),
path('student/', include(('student.urls', 'student'))),path('teacher/', include(('teacher.urls', 'teacher'))),
]
8 访问http://127.0.0.1:8000/teacher/query/
可以得到与第9节类似的页面