今天开始回顾一下老师页面的代码
先看下html的页面效果图
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
首先看下如何实现页面渲染老师列表,这里实现了两种方法
先看视图函数,老师页面对应的视图还是是teacher
然后我们来看视图函数
下面是视图函数所有的代码
@outer
def teacher(request):
if request.method == "GET":
from urtil import page
count = models.teacher.objects.all().count()
current_page = int(request.GET.get("p",1))
per_page_num = 10
base_url = request.path
teacher_dict = {}
t_page = page.page_helper(count,current_page,per_page_num,base_url)
# print(t_page.page_count())
t = models.teacher.objects.filter(id__in=models.teacher.objects.all()[t_page.db_start()-1:t_page.db_end()-1]).values("id","teacher_name","teacher_class__id","teacher_class__classes_name")
for i in t:
if i["id"] in teacher_dict.keys():
if i["teacher_class__id"] == None:
pass
else:
teacher_dict[i["id"]]["t_class_info"].append(
{
i["teacher_class__id"]: i["teacher_class__classes_name"],
}
)
else:
if i["teacher_class__id"] != None:
teacher_dict[i["id"]] = {
"t_name":i["teacher_name"],
"t_class_info":[
{
i["teacher_class__id"]:i["teacher_class__classes_name"],
}
]
}
else:
teacher_dict[i["id"]] = {
"t_name": i["teacher_name"],
"t_class_info":[]
}
page_str = t_page.page_list()
teacher_list = models.teacher.objects.all()[t_page.db_start()-1:t_page.db_end()-1]
return render(request,"teacher.html",locals())
else:
return HttpResponse("POST")
先看方法1是如何实现的
这里我们导入了我们自己写的page_helper的类,用来构建分页的效果
因为前端渲染,首先要拿到老师的id,老师的名称,老师所教的班级的id,老师所教的班级的名称,所有,我们先拿到所有的老师,然后通过page_helper的类进行分页,分页成功后,然后在通过values方法,拿到每个老师对应的班级的字典对象,然后把这个对象在前端渲染,我们先看下上面这个t打印出来是个什么东西
是一个QuerySet对象
这个时候我们在前端然后这个对象就可以了,我们看下前端是如何渲染的
先把前端所有的代码贴出来,然后在一一分析
{% extends "base.html" %}
{% block css %}
<style>
.tag{
border: 1px;
background-color: pink;
color: red;
font-size: 15px;
border-radius: 5px;
cursor: pointer;
}
tbody span:hover{
font-size: 20px;
}
table{
display: inline-block;
}
.page_class a{
color: red;
font-size: larger;
padding: 5px;
}
.shade{
position: fixed;
background-color: pink;
top: 0;
left: 0;
right: 0;
bottom: 0;
opacity: 0.8;
z-index: 100;
}
.modal{
position: fixed;
background-color: red;
color: black;
left: 50%;
top: 50%;
width: 200px;
height: 150px;
margin-left: -100px;
margin-right: -75px;
z-index: 101;
}
.hide{
display: none;
}
</style>
{% endblock %}
{% block right %}
<h1>老师管理</h1>
<p><a href="/app1/add_teacher/">添加老师</a></p>
<table border="1">
<caption>老师列表方式1</caption>
<thead>
<tr>
<th>老师id</th>
<th>老师名称</th>
<th>老师班级</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for obj in teacher_list %}
<tr>
<td>{{ obj.id }}</td>
<td>{{ obj.teacher_name }}</td>
<td>
{% for i in obj.teacher_class.all %}
<span class="tag">{{ i.classes_name }}</span><span class="tag">{{ i.id }}</span>
{% endfor %}
</td>
<td>
<a href="#">删除</a>|<a href="/app1/edit_teacher/?tid={{ obj.id }}">编辑1</a>|<a href="/app1/edit_teacher_new/?tid={{ obj.id }}">编辑2</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="page_class">
{{ page_str|safe }}
</div>
<table border="3">
<caption>老师列表方式2</caption>
<thead>
<tr>
<th>老师id</th>
<th>老师名称</th>
<th>老师班级</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for k,v in teacher_dict.items %}
<tr>
<td>{{ k }}</td>
<td>{{ v.t_name }}</td>
<td>
{% for c_info in v.t_class_info %}
{% for m,n in c_info.items %}
<span class="tag">{{ m}}</span><span class="tag">{{ n}}</span>
{% endfor %}
{% endfor %}
</td>
<td>
<a href="#">删除</a>|<a href="/app1/edit_teacher/">编辑1</a>|<a href="/app1/edit_teacher_new/">编辑2</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="page_class">
{{ page_str|safe }}
</div>
<div class="hide shade" id="ajax_del_class_shade">
hhhhhhhhhhh
</div>
<div class="hide modal" id="ajax_del_class_modal">
是否删除班级<span class="del_class"></span>
<input type="button" value="确定删除" class="ajax_del_teacher_class">
<input type="button" value="取消" class="not_ajax_del_teacher_class">
</div>
{% endblock %}
{% block jq %}
<script src="/static/jq/jquery-3.3.1.js"></script>
<script>
$(function () {
$("#menu_teacher").addClass("active");
del_teacher_class();
not_del_teacher_class();
});
function del_teacher_class() {
$(".tag").bind("click",function () {
$("#ajax_del_class_shade").removeClass("hide");
$("#ajax_del_class_modal").removeClass("hide");
})
}
function not_del_teacher_class() {
$(".tag").bind("click",function () {
$("#ajax_del_class_shade").addClass("hide");
$("#ajax_del_class_modal").addClass("hide");
})
}
</script>
{% endblock %}
先看第一种前端是如何渲染的
{% for obj in teacher_list %}
<tr>
<td>{{ obj.id }}</td>
<td>{{ obj.teacher_name }}</td>
<td>
{% for i in obj.teacher_class.all %}
<span class="tag">{{ i.classes_name }}</span><span class="tag">{{ i.id }}</span>
{% endfor %}
</td>
<td>
<a href="#">删除</a>|<a href="/app1/edit_teacher/?tid={{ obj.id }}">编辑1</a>|<a href="/app1/edit_teacher_new/?tid={{ obj.id }}">编辑2</a>
</td>
</tr>
{% endfor %}
我们看到一个老师对应的所有班级我们放在td中的不同的span标签中,同样我们对span标签做一个css处理
.tag{
border: 1px;
background-color: pink;
color: red;
font-size: 15px;
border-radius: 5px;
cursor: pointer;
}
tbody span:hover{
font-size: 20px;
}
同样也要显示分页,这里的分页,我们是通过管道付+safe来实现的
<div class="page_class">
{{ page_str|safe }}
</div>
同样我也为这个page_class弄一个样式,这样好看一些
.page_class a{
color: red;
font-size: larger;
padding: 5px;
}
在渲染的时候我们做了两层的循环
首先后端给前端一个老师的对象,然后由前端通过模板语言去数据库中查询数据,这里有一个问题就是会频繁的去查询数据库,这个方法不够好
第一层是循环所有的老师,当拿到一个老师的对象,在通过obj.teacher_class.all拿到这个老师对应的所有班级的信息,然后把班级的id和名称渲染到html页面行
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
第二种方法,就是后端直接把所有的数据准备好,然后把这个数据返回给前端就可以了,我们需要先在后端准备数据
首先在后端通过value的方法把老师的信息,老师对应的班级的信息全部拿到,放在一个字典中
我在后端循环处理上面的querySet对象,拿到我们想要的数据,我们的数据结构是这样的
teacher_id :{
t_name:teacher_name,
t_class_info:[
{t_class_Id:t_class_id}
]
}
首先是一个大的字典,id是为每个teacher的id,每个teacher的id对应的v值又是一个字典,这个字典的第一个k值是t_name,v值就是teacher_name,第二个k值为t_class_info,这个k值对应的v值是一个列表,而这个列表的每个元素是一个字典,这个字典的k值是t_class_id,v值是班级的id,
for i in t:
if i["id"] in teacher_dict.keys():
if i["teacher_class__id"] == None:
pass
else:
teacher_dict[i["id"]]["t_class_info"].append(
{
i["teacher_class__id"]: i["teacher_class__classes_name"],
}
)
else:
if i["teacher_class__id"] != None:
teacher_dict[i["id"]] = {
"t_name":i["teacher_name"],
"t_class_info":[
{
i["teacher_class__id"]:i["teacher_class__classes_name"],
}
]
}
else:
teacher_dict[i["id"]] = {
"t_name": i["teacher_name"],
"t_class_info":[]
}
然后我们在前端通过渲染字典的方式渲染这个大的字典即可
这样,我们在后端就通过一次数据库查询,拿到所有的数据,在通过组织数据结构,返回给前端,这样效率最高
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
下面我们看下添加老师是如何实现的
我们看url中这个url对应的视图函数
我们在到视图函数查看add_teacher这个函数是如何实现的
@outer
def add_teacher(request):
class_list = models.classes.objects.all()
if request.method == "GET":
return render(request,"add_teacher.html",locals())
else:
new_teacher_name = request.POST.get("new_add_teacher_name",None)
print("--------------------------------")
print(new_teacher_name)
if not new_teacher_name:
error = "名称不允许为空"
return render(request,"add_teacher.html",locals())
elif models.teacher.objects.filter(teacher_name=new_teacher_name).exists():
error = "名称{new_name}已经存在,请输入新的名字".format(new_name=new_teacher_name)
return render(request, "add_teacher.html", locals())
else:
new_class_list = request.POST.getlist("new_add_teacher_class",None)
print(new_class_list)
new_teacher = models.teacher.objects.create(
teacher_name = new_teacher_name
)
new_teacher.teacher_class.add(
*new_class_list
)
return redirect("/app1/teacher/")
首先如何是get请求,则需要把所有班级渲染到前端页面
class_list = models.classes.objects.all()
if request.method == "GET":
return render(request,"add_teacher.html",locals())
我们看下前端是如何渲染的
原来是一个form表单,里面有有一个input框,用来输入新的老师的名称,另外一个是一个select框,,这个select标签之前说的比较少,这里我在说一下
select的name属性,就是k值,
size是当前的框中显示几条数据
multiple是当前是多选的
看下前端的效果
在看后端是如何处理post请求的
这里需要注意,如果前端是select的方式向后端发送多选的信息,这里必须要通过request.POST.getlist(“k值”)去获取信息
new_teacher_name = request.POST.get("new_add_teacher_name",None)
print("--------------------------------")
print(new_teacher_name)
if not new_teacher_name:
error = "名称不允许为空"
return render(request,"add_teacher.html",locals())
elif models.teacher.objects.filter(teacher_name=new_teacher_name).exists():
error = "名称{new_name}已经存在,请输入新的名字".format(new_name=new_teacher_name)
return render(request, "add_teacher.html", locals())
else:
new_class_list = request.POST.getlist("new_add_teacher_class",None)
print(new_class_list)
new_teacher = models.teacher.objects.create(
teacher_name = new_teacher_name
)
new_teacher.teacher_class.add(
*new_class_list
)
return redirect("/app1/teacher/")
同样这里也做了一下判断,比如是否为空,是否存在,前端也是通过一个span标签来接受错误信息
如果判断都通过,则先使用create方法添加老师的对象
然后拿到老师的对象,在使用add方法为这个老师添加班级对象
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
然后我们看下编辑1的是如何实现的,编辑1我们的效果是前端只有一个select框
先看下效果
下面我们看下html的代码
是一个a标签,href指向一个新的url,且传递了一个参数t_id给后端
我们到后端去看下url
在看视图函数
@outer
def edit_teacher(request):
method = request.method.lower()
if method == "get":
t_name = models.teacher.objects.get(id=request.GET.get("tid")).teacher_name
t_id = request.GET.get("tid")
all_class_list = models.classes.objects.all()
select_class_list = models.teacher.objects.get(id=request.GET.get("tid")).teacher_class.all()
return render(request,"edit_teacher.html",locals())
else:
t_id = request.POST.get("t_id")
new_teacher_name = request.POST.get("new_edit_teacher_name")
new_class_list = request.POST.getlist("new_edit_class_list")
new_teacher = models.teacher.objects.filter(id=t_id).update(
teacher_name = new_teacher_name
)
models.teacher.objects.get(id=t_id).teacher_class.set(new_class_list)
return redirect("/app1/teacher")
先看下get方式的处理
先拿到老师的id,然后在拿到所有班级的列表,最后在拿到这个老师对应的所有的班级
然后把上面拿到信息发送给前端
if method == "get":
t_name = models.teacher.objects.get(id=request.GET.get("tid")).teacher_name
t_id = request.GET.get("tid")
all_class_list = models.classes.objects.all()
select_class_list = models.teacher.objects.get(id=request.GET.get("tid")).teacher_class.all()
return render(request,"edit_teacher.html",locals())
我们在看前端是怎么处理的
<h1>编辑老师1</h1>
<form method="post" action="/app1/edit_teacher/">
<input type="text" style="display: none" name="t_id" value="{{ t_id }}">
<p>
老师名称:<input type="text" placeholder="新的老师名称" name="new_edit_teacher_name" value="{{ t_name }}">
</p>
<p>
<select multiple="multiple" size="10" name="new_edit_class_list">
{% for i in all_class_list %}
{% if i in select_class_list %}
<option selected="selected" value="{{ i.id }}">{{ i.classes_name }}</option>
{% else %}
<option value="{{ i.id }}">{{ i.classes_name }}</option>
{% endif %}
{% endfor %}
</select>
</p>
<p>
<input type="submit" value="提交">
</p>
</form>
也是一个form表单,先渲染出当前老师的名称,然后循环所有的班级,在循环所有的班级的时候嵌套循环老师的班级,如果所有的班级中的某个元素在老师的班级中的list中,则给这个元素加一个select=“selected”,标记为选中状态
我们在视图函数中post方式是怎么处理的
拿到新的名称,新的class_list,通过update方法先更新老师的名称,然后通过id获取老师的对象,然后通过set方法更新老师的班级信息,set方法就是多对多的更新的方法
t_id = request.POST.get("t_id")
new_teacher_name = request.POST.get("new_edit_teacher_name")
new_class_list = request.POST.getlist("new_edit_class_list")
new_teacher = models.teacher.objects.filter(id=t_id).update(
teacher_name=new_teacher_name
)
models.teacher.objects.get(id=t_id).teacher_class.set(new_class_list)
return redirect("/app1/teacher")
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
下面看下第二种方法是如何实现的
然后我们看下视图函数
@outer
def edit_teacher_new(request):
method = request.method.lower()
if method == "get":
t_id = request.GET.get("tid")
t_name = models.teacher.objects.get(id=t_id).teacher_name
select_class_list = models.teacher.objects.get(id=t_id).teacher_class.all()
not_select_class_list = models.classes.objects.exclude(id__in=select_class_list)
return render(request,"edit_teacher_new.html",locals())
else:
t_id = request.POST.get("t_id")
t_name = request.POST.get("t_name")
new_class_list = request.POST.getlist("select_class_name",None)
print(t_id,t_name,new_class_list)
models.teacher.objects.filter(id=t_id).update(
teacher_name = t_name
)
models.teacher.objects.get(id=t_id).teacher_class.set(
new_class_list
)
return redirect("/app1/teacher/")
先看下get方式是怎么处理的
exclude是取反的意思,拿到id不在当前老师班级的列表中的班级
看下前端是否如何渲染的
<h1>编辑老师2</h1>
<form method="post" action="/app1/edit_teacher_new/">
<input class="hide" type="text" name="t_id" value="{{ t_id }}">
<input type="text" name="t_name" value="{{ t_name }}">
<div>
<span>已经绑定的班级</span>
<select multiple="multiple" size="10" name="select_class_name" id="select_left">
{% for i in select_class_list %}
<option value="{{ i.id }}">{{ i.classes_name }}</option>
{% endfor %}
</select>
</div>
<div>
<input type="button" value="------->" id="del_many_class">
<input type="button" value="<-------" id="add_many_class">
<input type="button" value="========>" id="del_all_class">
<input type="button" value="<========" id="add_all_class">
</div>
<div>
<select multiple="multiple" size="10" name="not_select_class_name" id="not_select_right">
{% for i in not_select_class_list %}
<option value="{{ i.id }}">{{ i.classes_name }}</option>
{% endfor %}
</select>
<span>未绑定的班级</span>
</div>
<hr>
<input type="submit" value="提交">|<a href="/app1/teacher/">返回</a>
</form>
看下具体的效果
写了2个select标签,第一个存放已经绑定的班级,第二个 存放为绑定的班级
只要我们可以实现左边的框移到到右边的框,右边的框可以移动到左边的框就可以了
重点看下4个按钮是如何实现的
第一个按钮,del_many_class实现从左边向右边移动一个或者多个班级。我们看下jquery的代码
主要是实现思路就是把左边的标签append到右边就可以了
第一步,通过dom的方式获取右边的select标签,这个就是我们将要往这个标签下面添加标签
第二步,通过dom的方式获取左边的select标签下面的所有标签
第三步,拿到左边标签的子标签的个数
第四步,执行for循环语句,判断左边的子标签如果select=true,则appendChild到右边,这个appendChild方法会向右边添加该标签,同时会删除左边的标签
第五步,这里为什么要执行一个i--语句呢,因为appendChild一个后,原来的列表就少一个标签,所有列表id要往前推一个
function del_many_class_func() {
$("#del_many_class").bind("click",function () {
var father_ele = document.getElementById("not_select_right")
var del_ele = document.getElementById("select_left").children
var del_ele_length = del_ele.length
for(var i=0;i<= del_ele_length;i++){
if(del_ele[i].selected==true){
del_ele[i].selected=false;
father_ele.appendChild(del_ele[i]);
i--
}
}
})
}
在看add_many_class的按钮
思路和上面的函数是一样的
function add_many_class_func() {
$("#add_many_class").bind("click",function () {
var father_ele = document.getElementById("select_left")
var del_ele = document.getElementById("not_select_right").children
var del_ele_length = del_ele.length
for(var i=0;i<=del_ele_length;i++){
if(del_ele[i].selected==true){
{# del_ele[i].selected=true;#}
father_ele.appendChild(del_ele[i])
i--
}
}
})
}
下面在看del_all_class,删除所有班级
第一步,获取右边的select的标签,作为父标签
第二步,获取左边标签的所有的子标签
第三步,获取左边标签的所有的子标签的个数
第四步,使用for循环,循环左边的子标签的长度,如果左边的子标签为select=true,则设在false,然后添加到右边,
function del_all_class_func() {
$("#del_all_class").bind("click",function () {
var father_ele = document.getElementById("not_select_right")
var del_ele = document.getElementById("select_left").children
var del_ele_length = del_ele.length
for(var i=0;i<=del_ele_length;i++){
if(del_ele[0].selected==true){
del_ele[0].selected=false;
}
father_ele.appendChild(del_ele[0])
}
})
}
第四个按钮,add_all_class
思路和上面的函数一样
function add_all_class_func() {
$("#add_all_class").bind("click",function () {
var father_ele = document.getElementById("select_left")
var del_ele = document.getElementById("not_select_right").children
var del_ele_length = del_ele.length
for(var i=0;i<=del_ele_length;i++){
if(del_ele[0].selected==false){
del_ele[0].selected=true;
}
father_ele.appendChild(del_ele[0])
}
})
}
最后在$function函数中绑定上面的四个函数即可
$(function () {
$("#menu_teacher").addClass("active")
del_many_class_func();
add_many_class_func();
del_all_class_func();
add_all_class_func();
submit()
})
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------