1. 程式人生 > >ORM版學員管理系統3

ORM版學員管理系統3

render remove etime ttr dev edge 列表 else dir

老師信息管理

思考

三種方式創建多對多外鍵方式及其優缺點。

通過外鍵創建

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創建

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)

clear()

從關聯對象集中移除一切對象。

>>> teacher_obj = models.Teacher.objects.first()
>>> teacher_obj.cid.clear()

註意:

對於ForeignKey對象,clear()和remove()方法僅在null=True時存在。

舉個例子:

ForeignKey字段沒設置null=True時,

class Student(models.Model):
    sname = models.CharField(max_length=32)
    cid = models.ForeignKey(to=Class, to_field="id")

沒有clear()和remove()方法:

>>> models.Class.objects.first().student_set.clear()
Traceback (most recent call last):
  File "<input>", line 1, in <module>
AttributeError: ‘RelatedManager‘ object has no attribute ‘clear‘

當ForeignKey字段設置null=True時,

class Student(models.Model):
    sname = models.CharField(max_length=32)
    cid = models.ForeignKey(to=Class, to_field="id", null=True)

此時就有clear()和remove()方法:

>>> models.Class.objects.first().student_set.clear()

註意:

  1. 對於所有類型的關聯字段,add()、create()、remove()和clear(),set()都會馬上更新數據庫。換句話說,在關聯的任何一端,都不需要再調用save()方法。

了不起的雙下劃線

在這之前我們所有的跨表查詢都是基於對象的查詢。

比如:

>>> models.Class.objects.first().student_set.values("sname")
<QuerySet [{‘sname‘: ‘張三‘}, {‘sname‘: ‘李四‘}, {‘sname‘: ‘小明‘}]>

Django還提供了一種直觀而高效的方式在查詢中表示數據表之間的關聯關系,它能自動確認 SQL JOIN 關系。

需要做跨關系查詢時,就可以使用兩個下劃線來鏈接模型(model)間關聯字段的名稱,直到最終鏈接到你想要的 model 為止。

>>> models.Class.objects.filter(id=1).values("student__sname")  # 雙下劃線表示跨表
<QuerySet [{‘student__sname‘: ‘張三‘}, {‘student__sname‘: ‘李四‘}, {‘student__sname‘: ‘小明‘}]>

ORM版學員管理系統3