ORM-老师信息系统

老师信息管理

思考

三种方式创建多对多外键方式及其优缺点。

通过外键创建

(自定义第三张表,通过外键与其他两张表关联  但是不能用Django ORM 多对多操作的语法)

class Class(models.Model):
    id = models.AutoField(primary_key=True)  # 主键
    cname = models.CharField(max_length=32)  # 班级名称
    first_day = models.DateField()  # 开班时间


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")

通过ManyToManyField创建

(通过ManyToManyField创建,Django会自动创建第三张关系表,但是此表没有相关的类与其对应,不能单独对此表操作)

(但是此表可以使用Django自带的功能,

 Teaccher.cid.all() 是Djando自带的功能,是一个中间桥梁(关联表),可以进行点点点操作,因为Teacher表和Class表没有直接关系

)

class Class(models.Model):
    id = models.AutoField(primary_key=True)  # 主键
    cname = models.CharField(max_length=32)  # 班级名称
    first_day = models.DateField()  # 开班时间


class Teacher(models.Model):
    tname = models.CharField(max_length=32)
    # 通过ManyToManyField自动创建第三张表
    cid = models.ManyToManyField(to="Class", related_name="teachers")

通过外键和ManyToManyField创建

(可以增加第三张表的字段 ,可以单独用第三张表进行相关操作)

class Class(models.Model):
    id = models.AutoField(primary_key=True)  # 主键
    cname = models.CharField(max_length=32)  # 班级名称
    first_day = models.DateField()  # 开班时间


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")

老师信息列表

URL部分

url(r'^teacher_list/$', app01_views.teacher_list, name="teacher_list"),

视图部分

def teacher_list(request):
    teacher_list = models.Teacher.objects.all()
    return render(request, "teacher_list.html", {"teacher_list": teacher_list})

前端部分

<!DOCTYPE html>
<html lang="zh-CN">
<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>
<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 %}
          {% if forloop.last %}
            {{ class.cname }}
          {% else %}
            {{ class.cname }},
          {% endif %}
        {% endfor %}
      </td>
      <td>
        <a href="{% url 'delete_teacher' teacher.id %}">删除</a>
        <a href="{% url 'edit_teacher' teacher.id %}">编辑</a>
      </td>
    </tr>
  {% endfor %}
  </tbody>
</table>
</body>
</html>

删除老师信息

URL部分

url(r'^delete_teacher/(?P<tid>d+)$', app01_views.delete_teacher, name="delete_teacher"),

视图部分

def delete_teacher(request, tid):
    models.Teacher.objects.filter(id=tid).delete()
    return redirect(reverse("teacher_list"))

前端部分

在老师列表页面添加一个删除的链接。

<a href="{% url 'delete_teacher' teacher.id %}">删除</a>

添加老师信息

URL部分 

url(r'^add_teacher/$', app01_views.add_teacher, name="add_teacher"),

视图部分

def add_teacher(request):
    if request.method == "POST":
        tname = request.POST.get("tname")
        class_ids = request.POST.getlist("class_id")
        new_teacher = models.Teacher.objects.create(tname=tname)
        # 查询出所有被选中的班级信息
        class_objs = models.Class.objects.filter(id__in=class_ids)
        # 将老师的授课班级设置为选中的班级, 以下四种都可以,注意什么时候加*
        new_teacher.cid.set(class_objs)
        # new_teacher.cid.add(*class_objs)
        # new_teacher.cid.add(*class_ids)
        # new_teacher.cid.set(class_ids)
        new_teacher.save()
        return redirect(reverse("teacher_list"))

    class_list = models.Class.objects.all()
    return render(request, "add_teacher.html", {"class_list": class_list})

前端部分

<!DOCTYPE html>
<html lang="zh-CN">
<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>老师姓名:<input type="text" name="tname"></p>
  <label for="class_id">授课班级:</label>
    <select name="class_id" id="class_id" multiple>
      {% for class in class_list %}
        <option value="{{ class.id }}">{{ class.cname }}</option>
      {% endfor %}
    </select>
    <p><input type="submit" value="提交"></p>
</form>
</body>
</html>

编辑老师信息

URL部分

url(r'^edit_teacher/(?P<tid>d+)$', app01_views.edit_teacher, name="edit_teacher"),

视图部分

def edit_teacher(request, tid):
    teacher_obj = models.Teacher.objects.get(id=tid)
    class_list = models.Class.objects.all()

    if request.method == "POST":
        tname = request.POST.get("tname")
        class_ids = request.POST.getlist("class_id")
        # 更新老师相关信息
        teacher_obj.tname = tname
        teacher_obj.cid.set(class_ids)
        teacher_obj.save()  # 一定记得更新完要保存
        return redirect(reverse("teacher_list"))

    return render(request, "edit_teacher.html", {"class_list": class_list, "teacher": teacher_obj})

前端部分

<!DOCTYPE html>
<html lang="zh-CN">
<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.id %}" method="post">
  {% csrf_token %}
  <p>老师姓名:<input type="text" name="tname" value="{{ teacher.tname }}"></p>
  <label for="class_id">授课班级:</label>
  <select name="class_id" id="class_id" multiple>
    {% for class in class_list %}
      {% if class in teacher.cid.all %}
        <option value="{{ class.id }}" selected>{{ class.cname }}</option>
      {% else %}
        <option value="{{ class.id }}">{{ class.cname }}</option>
      {% endif %}
    {% endfor %}
  </select>
  <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. 多对多关联关系

简单来说就是当 点后面的对象 可能存在多个的时候就可以使用以下的方法。

方法

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()    需要打散

把指定的model

对象添加到关联对象集中。

添加对象

>>> class_objs = models.Class.objects.filter(id__lt=3)
>>> models.Teacher.objects.first().cid.add(*class_objs)

添加id

>>> models.Teacher.objects.first().cid.add(*[1, 2])

set()   不需要打散

更新model对象的关联对象。

>>> teacher_obj = models.Teacher.objects.first()
>>> teacher_obj.cid.set([2, 3])

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时存在。

注意:

  1. 对于所有类型的关联字段,add()、create()、remove()和clear(),set()都会马上更新数据库。换句话说,在关联的任何一端,都不需要再调用save()方法。

了不起的双下划线

在这之前我们所有的跨表查询都是基于对象的查询。

比如:

找学生名字里面带龙字的班级
sname__contains=""
models.Class.objects.filter(students__sname__contains="")
双下划线表示跨表

Django还提供了一种直观而高效的方式在查询中表示数据表之间的关联关系,它能自动确认 SQL JOIN 关系。

需要做跨关系查询时,就可以使用两个下划线来链接模型(model)间关联字段的名称,直到最终链接到你想要的 model 为止

原文地址:https://www.cnblogs.com/caochao-/p/8344047.html