27.一对一,一对多,多对多关系表的各种骚操作

Posted 孤寒者

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了27.一对一,一对多,多对多关系表的各种骚操作相关的知识,希望对你有一定的参考价值。

1.关系表的数据操作

(1)一对多表关系的数据的添加修改

①学院表信息的插入:

常规方法是写个视图函数,在视图函数里添加插入数据的逻辑代码。但是这样的话——你得访问此视图函数对应的接口才能添加成功!岂不麻烦~
所以,本博主推出另一种简单的方法——如下图:直接执行插入数据的逻辑代码即可!(Tab键可自动补全代码哦!!!)

②学生表信息的插入(使用常规视图插入数据)

from django.http import HttpResponse

from .models import Department,Student,Course,Stu_detail
def add_user(request):

    #1.根据模型类层面的属性进行数据的添加            属性赋值的方法
    # 因为我们在模型类有定义了一个department的属性, 而这个属性对象的类型必须是department表的类实例对象
    d = Department.objects.get(d_id=1)                    #department表的实例对象
    Student.objects.create(s_name="小明",department=d)    #外键department的字段值必须department表的类实例对象

    #2.根据数据库层面的字段名进行数据的添加
    # 需要注意的是外键(查看学生表发现外键这个字段会自动在模型类定义的属性后面加个_id:department_id)的值必须是关联表中已经存在的值.
    Student.objects.create(s_name="小红", department_id=2)

    return HttpResponse("插入数据成功!")

③观察可知插入成功:

(2)表关联对象的访问:

①基操——普通方式


②进阶——正向查询

(注意点:凡是在模型类定义阶段设置了外键的属性,对应生成数据表时都会在其后加上_id。如果想单纯获取这个值,可以就数据库层面查询,使用.此属性_id即可)

正向查询:Student的模型类中我们有定义department的属性,所以当我们去访问的时候,可以直接通过student.department的形式去找到某个学生所属学院的实例对象,进而查询其所属学院的所有信息。
由此发出灵魂拷问:
如果我们也希望在在访问某个学院的实例对象的学生的时候该怎么访问呢???
这就用到了接下来要讲的——反向查询!!!

③终极版——反向查询

反向查询:如果模型Student有一个ForeignKey(会自动给对应的Department类添加一个反向查询的属性!),那么该ForeignKey 所指的模型Department实例可以通过一个管理器回到前面有ForeignKey的模型Studnet的所有实例。默认情况下,这个管理器的名字为student_set(可以在对应的表关联API中通过设置related_name的值来自定义),其中student是源模型的小写名称。

拓展:两个表关联的API(OneToOne,Foreignkey,ManyToMany)在谁那,通过谁去查询另一个表的信息就是正向查询;反之就是反向查询。
注意:只限一对多以及多对多;一对一没有_set属性,无法使用!!!


拓展:

可以在定义时设置related_name 参数来覆盖student_set的名称!


③.1 终极版——反向查询的一些常用方法

注意:只限一对多以及多对多;一对一没有_set属性,无法使用!!!

from django.http import HttpResponse

from .models import Department,Student,Course,Stu_detail

def add_user(request):

    d = Department.objects.get(d_id=1)                     #学院表中北大的实例
    d3 = Department.objects.get(d_id=3)                    #学院表中中科的实例

    # create()方法:新建数据
    d.student_set.create(s_name="小王")     #在北大院系下新建一个学生表信息

    # add()方法:修改已经存在的数据(注意:通过实例)
    s3 = Student.objects.get(s_id=2)        #将s_id为2的学生的院系从北大换到中科
    d3.student_set.add(s3)

    return HttpResponse("插入数据成功!")

原始表中数据:
访问上述视图函数对应接口后的数据:


④一对一表信息的访问

(注意:一对一表关系中使用不了反向查询!!!)

from django.http import HttpResponse

from .models import Department,Student,Course,Stu_detail


def add_user(request):
    s1 = Student.objects.get(s_id=1)  # 获得一个学生的实例对象
    # 注意:一对一关系的话,反向查询不能使用。所以添加数据只能如下:
    Stu_detail.objects.create(Student=s1, age=18, phone=123456)

    print(s1.stu_detail)
    print(dir(s1.stu_detail))  # 会发现没有反向查询_set的属性!
    print(s1.stu_detail.age)  # 只能进行数据查询,不能添加!

    # 获取某个学生详情信息,正向查询查出其姓名(先正向查询到其Student实例对象,再获取s_name属性值)
    d = Stu_detail.objects.get(id=1)
    print(d.Student)
    print(d.Student.s_name)

    return HttpResponse("插入数据成功!")

输出:

Stu_detail<age=18,phone=123456>
['DoesNotExist', 'MultipleObjectsReturned', 'Student', 'Student_id', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_check_column_name_clashes', '_check_field_name_clashes', '_check_fields', '_check_id_field', '_check_index_together', '_check_indexes', '_check_local_fields', '_check_long_column_names', '_check_m2m_through_same_relationship', '_check_managers', '_check_model', '_check_model_name_db_lookup_clashes', '_check_ordering', '_check_property_name_related_field_accessor_clashes', '_check_single_primary_key', '_check_swappable', '_check_unique_together', '_do_insert', '_do_update', '_get_FIELD_display', '_get_next_or_previous_by_FIELD', '_get_next_or_previous_in_order', '_get_pk_val', '_get_unique_checks', '_meta', '_perform_date_checks', '_perform_unique_checks', '_save_parents', '_save_table', '_set_pk_val', '_state', 'age', 'check', 'clean', 'clean_fields', 'date_error_message', 'delete', 'from_db', 'full_clean', 'get_deferred_fields', 'id', 'objects', 'phone', 'pk', 'prepare_database_save', 'refresh_from_db', 'save', 'save_base', 'serializable_value', 'unique_error_message', 'validate_unique']
18
Student<s_id=1,s_name=小明>
小明

⑤多对多表信息的操作

第一部分:数据的添加及关联:

首先,课程表中添加数据:

from django.http import HttpResponse

from .models import Department,Student,Course,Stu_detail


def add_user(request):
    Course.objects.create(c_name="python")
    Course.objects.create(c_name="java")
    Course.objects.create(c_name="web前端")
    Course.objects.create(c_name="c++")

    return HttpResponse("插入数据成功!")


此时,学生表也有了,下面要做的就是通过中间表将两个表关联起来!


然后,关联表:

from django.http import HttpResponse

from .models import Department,Student,Course,Stu_detail

def add_user(request):
    s1 = Student.objects.get(s_id=1)        #小明
    s2 = Student.objects.get(s_id=2)        #小红
    c1 = Course.objects.get(c_id=1)         #python
    #1.数据库中已存在的数据       将学生表和课程表通过Django自动生成的中间表联系起来
    s1.course.add(c1)
    #2.数据库中没有的数据          将学生小红与新建的课程"人工智能"联系起来
    s2.course.create(c_name="人工智能")

    return HttpResponse("插入数据成功!")

没有执行之前Django自动生成的中间表是空的:

执行之后Django自动生成的中间表:

第二部分:指定数据的删除及全部删除

from django.http import HttpResponse

from .models import Department,Student,Course,Stu_detail


def add_user(request):
    s1 = Student.objects.get(s_id=1)        #小明
    s2 = Student.objects.get(s_id=2)        #小红
    c1 = Course.objects.get(c_id=1)         #python
    s1.course.remove(c1)                #删除小明同学的课程python

    s2.course.clear()                   #删除小红同学的所有课程

    return HttpResponse("插入数据成功!")

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

❤️可以扫码关注本人公众号——任何问题都可在公众号提问(定时有专人解答);并且不定时更新干货文。欢迎关注哦!❤️

以上是关于27.一对一,一对多,多对多关系表的各种骚操作的主要内容,如果未能解决你的问题,请参考以下文章

mysql表的一对一/一对多/多对多联系

Hibernate映射关系:一对一对多和多对多

django mysql 表的一对一 一对多 多对多

数据库设计中一对多对多对多关系依据外键的实现条件及方法

数据库一对一对多多对多关系

MySQL 表的一对一对多多对多问题