一、老师信息管理
思考:三种方式创建多对多外键方式及优缺点
1、通过外键创建
class Class(models.Model): id = models.AutoField(primary_key=True) # 主键 cname = models.CharField(max_length=20) # 班级名称 first_day = models.DateField() # 开班时间 # 方法一:自定义第三张表,通过外键关联teacher表和class表 class Teacher(models.Model): tname = models.CharField(max_length=32) class Teacher2Class(models.Model): teacher = models.ForeignKey(to="Teacher") the_class = models.ForeignKey(to="Class") class Meta: unique_together = ("teacher", "the_class")
2、通过 ManyToManyField 创建
class Class(models.Model): id = models.AutoField(primary_key=True) # 主键 cname = models.CharField(max_length=20) # 班级名称 first_day = models.DateField() # 开班时间 # 方法二:通过ManyToManyField创建 class Teacher(models.Model): tname = models.CharField(max_length=32) # # 通过ManyToManyField来自动创建第三张表, # # 但是第三张表是Django帮你维护的, # # 不能直接对第三张表进行操作,但是可以使用Django给你提供的便捷操作 cid = models.ManyToManyField(to="Class", related_name="teachers", null=True) # # 表示在进行反向查询的时候可以使用related_name的值teachers来查找,不使用teacher_set def __str__(self): return self.tname
3、通过外键和 ManyToManyField 创建
class Class(models.Model): id = models.AutoField(primary_key=True) # 主键 cname = models.CharField(max_length=20) # 班级名称 first_day = models.DateField() # 开班时间 # 方法三:通过外键和ManyToManyField创建 # 这种方法不能使用Django给我们封装好的便捷的查询方法, # 但是可以直接操作第三张表,比较容易理解 # 在你想要对第三张表进行扩展或者单独操作的时候使用这种方法 class Teacher(models.Model): tname = models.CharField(max_length=32) # 通过ManyToManyField和手动创建第三张表 cid = models.ManyToManyField(to="Class", through="Teacher2Class", through_fields=("teacher", "the_class")) class Teacher2Class(models.Model): teacher = models.ForeignKey(to="Teacher") the_class = models.ForeignKey(to="Class") class Meta: unique_together = ("teacher", "the_class")
二、表结构设计
class Teacher(models.Model): tname = models.CharField(max_length=32) cid = models.ManyToManyField(to="Class", related_name="teachers", null=True) def __str__(self): return self.tname
三、老师信息列表
1、url 部分
url(r'^teacher_list', views.teacher_list, name="teacher_list"),
2、视图部分
# 显示所有教师 def teacher_list(request): teacher_list = models.Teacher.objects.all() return render(request, "teacher_list.html", {"teacher_list": teacher_list})
3、前端部分
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> {# <link rel="stylesheet" href="bootstrap-3.3.7/css/bootstrap.min.css">#} <title>教师信息</title> </head> <body> <a href="{% url 'add_teacher' %}">添加班级</a> <table border="1"> <thead> <tr> <th>#</th> <th>教师ID</th> <th>教师姓名</th> <th>授课班级</th> <th>操作</th> </tr> </thead> <tbody> {% for teacher in teacher_list %} <tr> <td>{{ forloop.counter }}</td> <td>{{ teacher.id }}</td> <td>{{ teacher.tname }}</td> <td> {% for class in teacher.cid.all %} {{ class.cname }} {% endfor %} </td> <td><a href="{% url 'del_teacher' teacher.id %}">删除</a> <a href="{% url 'edit_teacher' teacher.id %} ">编辑</a> </td> </tr> {% endfor %} </tbody> </table> </body> </html>
四、删除老师信息
1、URL 部分
url(r'^del_teacher/(d+)', views.del_teacher, name="del_teacher"),
2、视图部分
def del_teacher(request, arg): models.Teacher.objects.filter(id=arg).delete() return redirect(reverse("teacher_list"))
3、前端部分
在老师列表页面添加一个删除的链接
<a href="{% url 'del_teacher' teacher.id %}">删除</a>
五、添加老师信息
1、URL 部分
url(r'^add_teacher', views.add_teacher, name="add_teacher"),
2、视图部分
def add_teacher(request): if request.method == "POST": tname = request.POST.get("tname") t_cids = request.POST.getlist("cid") teacher_obj = models.Teacher.objects.create(tname=tname) if t_cids: # 这是直接去数据库插入一条数据 # teacher_obj = models.Teacher.objects.create(tname=tname) # teacher_obj.cid.add(*t_cids) # 这是添加一个class对象 # 添加多个时如果使用add的时候需要在前面加上*进行打散 class_objs = models.Class.objects.filter(id__in=t_cids) teacher_obj.cid.add(*class_objs) return redirect(reverse("teacher_list")) class_list = models.Class.objects.all() return render(request, "add_teacher.html", {"class_list": class_list})
3、前端部分
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>添加老师</title> </head> <body> <form action="{% url 'add_teacher' %}" method="post"> {% csrf_token %} <p><label for="">老师姓名<input type="text" name="tname"></label></p> <label for="class_id">授课班级</label> <select name="cid" id="class_id" multiple> {% for class in class_list %} <option value="{{ class.id }}">{{ class.cname }}</option> {% endfor %} </select> <p><label><input type="submit" value="提交"></label></p> </form> </body> </html>
六、编辑老师信息
1、URL 部分
地方
url(r'^edit_teacher/(d+)', views.edit_teacher, name="edit_teacher"),
2、视图部分
def edit_teacher(request, arg): teacher_li = models.Teacher.objects.get(id=arg) print("*" * 120) print(teacher_li.cid.all) class_li = models.Class.objects.all() if request.method == "POST": tname = request.POST.get("tname") t_cids = request.POST.getlist("cid") # 更新老师信息 # 先更新老师表 teacher_li.tname=tname teacher_li.save() # 当添加多个时如果使用set更新表则不用加*进行打散操作 teacher_li.cid.set(t_cids) return redirect(reverse("teacher_list")) return render(request, "edit_teacher.html", {"class_list": class_li, "teacher_list": teacher_li})
3、前端部分
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>编辑老师</title> </head> <body> <form action="{% url 'edit_teacher' teacher_list.id %}" method="post"> {% csrf_token %} <p><label><input type="text" name="id" hidden value="{{ teacher_list.id }}"></label></p> <p>老师姓名:<label><input type="text" name="tname" value="{{ teacher_list.tname }}"></label></p> <p>授课班级: <select name="cid" id="" multiple> {% for class in class_list %} {% if class in teacher_list.cid.all %} <option selected value="{{ class.id }}">{{ class.cname }}</option> {% else %} <option value="{{ class.id }}">{{ class.cname }}</option> {% endif %} {% endfor %} </select> </p> <p><input type="submit" value="提交"></p> </form> </body> </html>
七、多对多操作
正向查询(由老师表查询班级表)
>>> teacher_obj = models.Teacher.objects.first() >>> teacher_obj.cid.all() # 查询该老师授课的所有班级 <QuerySet [<Class: Class object>, <Class: Class object>]>
反向查询(由班级列表反向查询老师表)
>>> class_obj = models.Class.objects.first() >>> class_obj.teachers.all() # 此处用到的是related_name,如果不设置的话就用默认的表名_set <QuerySet [<Teacher: Teacher object>, <Teacher: Teacher object>, <Teacher: Teacher object>]>
八、class RelatedManager
"关联管理器" 是在一对多或多对多中关联上下文使用的管理器。
在下面两种情况下存在:
1、外键关系的反向查询
2、多对多关联关系
简单来说就是当 点后面的对象 可能存在多个的时候就可以使用以下方法。
1、方法
create()
创建一个新的对象,保存对象,并将它添加到关联对象集之中,返回新创建的对象。
>>> import datetime >>> teacher_obj.cid.create(cname="9班", first_day=datetime.datetime.now())
创建一个新的学生对象,保存对象,并将它添加到关联的班级之中,返回新创建的对象。
>>> class_obj = models.Class.objects.first() # 查询班级表中的第一个班级 >>> class_obj.student_set.create(sname="小明") # 创建一个名叫小明的学生,并将小明添加到该班级中
多对多如何操作?
>>> class_obj = models.Class.objects.first() >>> class_obj.teacher_set.create(tname="老师X")
add() 在添加的时候如果是一个列表,则需要使用*[1, 2,3] 将列表进行打散
把指定的model 对象添加到关联对象集中。
添加对象
>>> class_objs = models.Class.objects.filter(id__lt=3)
>>> models.Teacher.objects.first().cid.add(*class_objs)
添加 id
>>> models.Teacher.object.first().cid.add(*[1, 2])
set() 当添加的时候如果是一个列表,不需要打散就可以添加进去
更新 model 对象的关联对象。
>>> teacher_obj = models.Teacher.objects.first() >>> teacher_obj.cid.set([2, 3]) # 上面的代码可以直接写成一句 >>> models.Teacher.objects.first().cid.set([1, 2])
remove() :从关联对象集中移除执行的 model 对象
>>> teacher_obj = models.Teacher.objects.first()
>>> teacher_obj.cid.remove(3)
对于 ForeignKey 对象,这个方法仅在 null=True 时存在
clear():从关联对象集中移除一切对象。
>>> teacher_obj = models.Teacher.objects.first()
>>> teacher_obj.cid.clear()
同理,对于 ForeignKey 对象,这个方法仅在 null=True 时存在。
注意:
对于所有类型的关联字段,add()、create()、remove() 和 clear(),set() 都会马上更新数据库。换句话说,在关联的任何一端,都不需要再调用 save() 方法。
九、了不起的双下划线
在这之前,我们所有的跨表查询都是基于对象的查询。
比如:
Django 还提供了一种直观而高效的方式在查询中表示数据表之间的关联关系,它能自动确认 SQL JOIN 关系。
需要做跨关系查询时,就可以使用两个下划线来链接模型( model) 间关联字段的名称,直到最终链接到你想要的 model 为止。