• 周日. 9月 25th, 2022

5G编程聚合网

5G时代下一个聚合的编程学习网

热门标签

Django ORM多表操作

admin

11月 28, 2021

ORM的注意事项

  • nid = models.AutoField(primary_key=True) ID字段是自动添加的,需要自定义变量名可以自己填写.
  • 对于外键字段,Django会在字段名上添加_id来创建数据库中的别名
  • 外链字段Foreignkey有一个null=true的设置,它允许外链接受空值null,可以给赋空值None.

多表关系的操作概要

  • 1对1的关系在两张表任意一张建立关联字段并且加Unique,比如
作者表 author
 id  name  age
  1  alex  18
  2  blex  30
  3  clex  25

作者个人信息表 authordetail
  id  addr  gender  tel  author_id(Unique)
  1    北京  男      123     1
  2    南京  女      1234    2
  3    上海  人妖    3311    3

create table authordetail(
  id int primary key auto_increment,
  addr varchar(20),
  gender enum("male","female"),
  tel int(11)
  author_id int unique,

);

  • 1对多的关系 需要在多个关系的表中建立关联字段
出版社 publish
 id  name      book
  1  北京出版社  18
  2  南京出版社  30
  3  天津出版社  25

create table publish(
  id int primary key auto_increment,
  name varchar(20)
);


书籍  book  在书籍和出版社对应关系中,一个出版社会出版多本书籍,因此把多个出版社id放在book表中创建一对多的关系,并且==要建立约束==,创建关系是为了查询,创建约束是为了防止产生脏数据
  id bookname  price  publish_id
  1  python      10        1
  2  java        20        1
  3  go          58        2
  4  php         79        3
 
create table book(
  id int primary key auto_increment,
  bookname varchar(20),
  price    decimal(8,2),
  publish_id int,
  foreign key(publish_id) reference book(id),


);
  • 多对多的关系 创建第三张关系表
书籍 book
 id  name      price    publish_id
  1  python      18          1
  2  java        30          1
  3  go          25          2

create table book(
  id int primary key auto_increment,
  name varchar(32),
  price decimal(5,2),
  publish_id int,
  foreign key (publish_id) reference publish(id),
);


作者表 author
 id  name  age
  1  alex  18
  2  blex  30
  3  clex  25

create table author(
  id int primary key auto_increment,
  name varchar(32),
  age int,
);

做着书籍关系表 book2auther

  id  book_id  author_id
  1      1        1
  2      1        2
  3      2        1
  4      3        2
create table book2auther(
  id int primary key auto_increment,
  book_id int,
  author_id int,
  foreign key (book_id) reference book(id),
  foreign key (author_id) reference author(id),
);



create table publish(
  id int primary key auto_increment,
  name varchar(20)
);

那么上面的sql语句在ORM中是怎么创建的呢,下面拿着SQL语法 举例在ORM中的语法

1. 出版社和书本的一对多关系


on_delete有6个可选值,分别是:
CASCADE 删除级联,当父表的记录删除时,子表中与其相关联的记录也会删除。即:当一个老师被删除时,关联该老师的学生也会被删除。
PROTECT 子表记录所关联的父表记录被删除时,会报ProtectedError异常。即:当一个学生所关联的老师被删除时,会报ProtectedError异常。
SET_NULL 子表记录所关联的父表记录被删除时,将子表记录中的关联字段设为NULL,注意:需要允许数据表的该字段为NULL。
SET_DEFAULT 子表记录所关联的父表记录被删除时,将子表记录中的关联字段设为一个给定的默认值。
DO_NOTHING 子表记录所关联的父表记录被删除时,什么也不做。
SET() 设置为一个传递给SET()的值或者一个回调函数的返回值,该参数用得相对较少。

2. 作者和作者详情的一对一关系

3. 书本和作者多对多的关系


我们可以看下手动创建的Book2Author 和ManyToMany创建的 book_author表,实现的效果是一样的.

orm一对多表之添加记录操作

class Publish(models.Model):
    nid = models.AutoField(primary_key=True)
    publish = models.CharField(max_length=32)
    def __str__(self):
        return self.publish

class book(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=20)
    price = models.DecimalField(max_digits=8, decimal_places=2)
    pub_date = models.DateField()
    publish = models.ForeignKey(to="Publish", to_field="nid",on_delete=models.CASCADE)

出版社和图书的对应关系为 一个出版社对应多本书,把对应关系写在book类中
出版社数据添加不多说,因为很简单,pub = models.Publish.objects.create(publish="南京出版社")
图书中的添加语法有2种,因为book中的publish在数据库中会自动进行字符串拼接为publish_id

  • 第一种book = models.book.objects.create(title="c++",price=18,pub_date = "2012-05-07",publish_id=2) publish_id直接写死
  • 第二种如下,此时book.title是java,book.price是28,但是book.publish 其实就是pub这个对象了,他包含了出版社的信息,所以book.publish.publish就是出版社的名字(南京出版社)
pub = models.Publish.objects.filter(publish="南京出版社").first()  #先对Publish表进行筛选出南京出版社的对象,再把这个对象放到publish的参数中去,等同于publish_id=南京的id
book = models.book.objects.create(title="java",price=28,pub_date = "2014-05-07",publish=pub)

orm多对多表之添加记录操作

class Book(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8, decimal_places=2)
    publish = models.ForeignKey(to="Publish", to_field="pid", on_delete=models.CASCADE)
    author = models.ManyToManyField(to="Author")

class Author(models.Model):
    aid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    author_detail = models.OneToOneField(to="Author_detail", to_field="aid", on_delete=models.CASCADE)

多对多添加也是第一步也是先获取一个对象,比如作者和书籍的关系,因为author这个字段在Book表中进行多对多的表(app1_book_author)的添加,我们先获取author对象

  1. alex = models.Author.objects.filter(name="alex").first() blex = models.Author.objects.get(name="blex") alex和blex就是作者的model对象
  2. 先创建Book的id title price 以及一对多的Publish字段 bk = models.Book.objects.create(title="java",price=29,publish_id=2) #书名叫Java的对象
  3. 通过Book下的author字段添加多对多关系,通过add()方法添加,可以加对象,也可以直接加id号,也可以用列表形式,除了添加还有remove方法和all()方法可以删除和查询多对多关系
    bk.author.add(alex,blex) #利用book类下的author字段,这个字段就是获取了manytomany的对象
    bk.author.add(1,2)
    bk.author.add(*[alex,blex])   

orm多对多表之更改记录操作

比如还是作者和书籍的多对多关系,第一步还是先获取筛选对象 bk = models.Book.objects.create(title="java", price=28.23, publish=pub)
然后有2种方法

第一种方法
bk.author.clear() 先清除他们的关系
bk.author.add(3,4)在按照上面新增一个关系

第二种方法用set(list) set会在新增之前把原先关系删除,而且里面默认放的就是列表,也不用加*
bk.author.set([3,4])

ORM的注意事项

  • nid = models.AutoField(primary_key=True) ID字段是自动添加的,需要自定义变量名可以自己填写.
  • 对于外键字段,Django会在字段名上添加_id来创建数据库中的别名
  • 外链字段Foreignkey有一个null=true的设置,它允许外链接受空值null,可以给赋空值None.

多表关系的操作概要

  • 1对1的关系在两张表任意一张建立关联字段并且加Unique,比如
作者表 author
 id  name  age
  1  alex  18
  2  blex  30
  3  clex  25

作者个人信息表 authordetail
  id  addr  gender  tel  author_id(Unique)
  1    北京  男      123     1
  2    南京  女      1234    2
  3    上海  人妖    3311    3

create table authordetail(
  id int primary key auto_increment,
  addr varchar(20),
  gender enum("male","female"),
  tel int(11)
  author_id int unique,

);

  • 1对多的关系 需要在多个关系的表中建立关联字段
出版社 publish
 id  name      book
  1  北京出版社  18
  2  南京出版社  30
  3  天津出版社  25

create table publish(
  id int primary key auto_increment,
  name varchar(20)
);


书籍  book  在书籍和出版社对应关系中,一个出版社会出版多本书籍,因此把多个出版社id放在book表中创建一对多的关系,并且==要建立约束==,创建关系是为了查询,创建约束是为了防止产生脏数据
  id bookname  price  publish_id
  1  python      10        1
  2  java        20        1
  3  go          58        2
  4  php         79        3
 
create table book(
  id int primary key auto_increment,
  bookname varchar(20),
  price    decimal(8,2),
  publish_id int,
  foreign key(publish_id) reference book(id),


);
  • 多对多的关系 创建第三张关系表
书籍 book
 id  name      price    publish_id
  1  python      18          1
  2  java        30          1
  3  go          25          2

create table book(
  id int primary key auto_increment,
  name varchar(32),
  price decimal(5,2),
  publish_id int,
  foreign key (publish_id) reference publish(id),
);


作者表 author
 id  name  age
  1  alex  18
  2  blex  30
  3  clex  25

create table author(
  id int primary key auto_increment,
  name varchar(32),
  age int,
);

做着书籍关系表 book2auther

  id  book_id  author_id
  1      1        1
  2      1        2
  3      2        1
  4      3        2
create table book2auther(
  id int primary key auto_increment,
  book_id int,
  author_id int,
  foreign key (book_id) reference book(id),
  foreign key (author_id) reference author(id),
);



create table publish(
  id int primary key auto_increment,
  name varchar(20)
);

那么上面的sql语句在ORM中是怎么创建的呢,下面拿着SQL语法 举例在ORM中的语法

1. 出版社和书本的一对多关系


on_delete有6个可选值,分别是:
CASCADE 删除级联,当父表的记录删除时,子表中与其相关联的记录也会删除。即:当一个老师被删除时,关联该老师的学生也会被删除。
PROTECT 子表记录所关联的父表记录被删除时,会报ProtectedError异常。即:当一个学生所关联的老师被删除时,会报ProtectedError异常。
SET_NULL 子表记录所关联的父表记录被删除时,将子表记录中的关联字段设为NULL,注意:需要允许数据表的该字段为NULL。
SET_DEFAULT 子表记录所关联的父表记录被删除时,将子表记录中的关联字段设为一个给定的默认值。
DO_NOTHING 子表记录所关联的父表记录被删除时,什么也不做。
SET() 设置为一个传递给SET()的值或者一个回调函数的返回值,该参数用得相对较少。

2. 作者和作者详情的一对一关系

3. 书本和作者多对多的关系


我们可以看下手动创建的Book2Author 和ManyToMany创建的 book_author表,实现的效果是一样的.

orm一对多表之添加记录操作

class Publish(models.Model):
    nid = models.AutoField(primary_key=True)
    publish = models.CharField(max_length=32)
    def __str__(self):
        return self.publish

class book(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=20)
    price = models.DecimalField(max_digits=8, decimal_places=2)
    pub_date = models.DateField()
    publish = models.ForeignKey(to="Publish", to_field="nid",on_delete=models.CASCADE)

出版社和图书的对应关系为 一个出版社对应多本书,把对应关系写在book类中
出版社数据添加不多说,因为很简单,pub = models.Publish.objects.create(publish="南京出版社")
图书中的添加语法有2种,因为book中的publish在数据库中会自动进行字符串拼接为publish_id

  • 第一种book = models.book.objects.create(title="c++",price=18,pub_date = "2012-05-07",publish_id=2) publish_id直接写死
  • 第二种如下,此时book.title是java,book.price是28,但是book.publish 其实就是pub这个对象了,他包含了出版社的信息,所以book.publish.publish就是出版社的名字(南京出版社)
pub = models.Publish.objects.filter(publish="南京出版社").first()  #先对Publish表进行筛选出南京出版社的对象,再把这个对象放到publish的参数中去,等同于publish_id=南京的id
book = models.book.objects.create(title="java",price=28,pub_date = "2014-05-07",publish=pub)

orm多对多表之添加记录操作

class Book(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8, decimal_places=2)
    publish = models.ForeignKey(to="Publish", to_field="pid", on_delete=models.CASCADE)
    author = models.ManyToManyField(to="Author")

class Author(models.Model):
    aid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    author_detail = models.OneToOneField(to="Author_detail", to_field="aid", on_delete=models.CASCADE)

多对多添加也是第一步也是先获取一个对象,比如作者和书籍的关系,因为author这个字段在Book表中进行多对多的表(app1_book_author)的添加,我们先获取author对象

  1. alex = models.Author.objects.filter(name="alex").first() blex = models.Author.objects.get(name="blex") alex和blex就是作者的model对象
  2. 先创建Book的id title price 以及一对多的Publish字段 bk = models.Book.objects.create(title="java",price=29,publish_id=2) #书名叫Java的对象
  3. 通过Book下的author字段添加多对多关系,通过add()方法添加,可以加对象,也可以直接加id号,也可以用列表形式,除了添加还有remove方法和all()方法可以删除和查询多对多关系
    bk.author.add(alex,blex) #利用book类下的author字段,这个字段就是获取了manytomany的对象
    bk.author.add(1,2)
    bk.author.add(*[alex,blex])   

orm一对多和多对多 基于对象跨表查询

数据库查询有2种,一种是子查询,一个子查询作为另一个查询语句的结果,第二种是join查询,把N张表通过关联组成一张大表,然后再提取里面的数据.

跨表查询对应的就是第一种子查询语句.跨表查询分 正向查询和反向查询.

正向查询按字段:关联字段在A表, 通过A查B, 反向查询按表名(表名小写_set):关联字段在A表, 通过B查A

    #一对多 正向查询,查python书籍的出版社名字
    bk = models.Book.objects.get(title="python")
    print(bk.publish.name)

    # 一对多 反向查询,查南京出版社出版的所有书籍
    pub=models.Publish.objects.get(name="南京出版社")
    print(pub.book_set.all())  #表名_set 返回的是个queryset对象集合

    # 多对多 正向查询,查python书籍对应的所有作者名字
    bk = models.Book.objects.get(title="python")
    print([i.name for i in bk.author.all()])

    # 多对多 反向查询,查blex作者对应的所有书籍名称
    au = models.Author.objects.get(name="blex")
    print([i.title for i in au.book_set.all()])

orm一对一 基于对象跨表查询

正向查询和一对多 多对多一样,但是反向查询有点不同,因为是一对一,不会有多个结果,
所以,结果也不会是queryset,语法也不用是小写表名_set,而是小写表名,例如 auth_detail.author.name

# 一对一
    # 正向查询
    au = models.Author.objects.filter(name="blex").first()
    print(au.author_detail.add)
    # 反向查询
    auth_detail = models.Author_detail.objects.filter(add="鄞州区").first()
    print(auth_detail.author.name)

orm 一对多和多对多查询 基于join查询

    #跨表inner join查询 都是在orm语法中就是和values方法
    bk = models.Author.objects.filter(name="alex").values("age")
    bk2 = models.Author.objects.filter(name="alex").values_list("age", "author_detail")
    print(bk)
    print(bk2)

    #基于双下划线的跨表查询 (join查询)  一对多.
    #方式一     正常查询按表名,不过表名语法略有不同,是表名__字段,values里面 publish__name意思是Publish表中的name字段

    bk3=models.Book.objects.filter(title="java").values("publish__name")
    print(bk3)
    #方式二 反向查询,通过出版社过滤book表中titile为python的对象,然后提取出版社的name字段
    bk4 = models.Publish.objects.filter(book__title="python").values("name")
    print(bk4)

    # 基于双下划线的跨表查询(join查询) 多对多查询 查询java书籍的所有作者和alex写的书籍
    #方式一 正向查询按字段
    bk5 = models.Book.objects.filter(title="java").values("author__name")
    print(bk5)
    # 方式二 反向查询按表名__字段 通过作者查询书名
    auth = models.Author.objects.filter(name="alex").values("book__title")
    print(auth)

基于双下划线的跨表查询(join查询) 一对一查询的正向查询和反向查询语句和上述并无二样. 不做举例.

基础双下划线的连续跨表查询(join查询)

#连续跨表查询 ,查到城市以宁波开头的作者出版过的书籍和对应的出版社名字
    #方式一 正向查询
    #假如以book为起始对象,book关联了作者表和出版社表,但是并未直接关联作者详情的表.我们需要多表跨表查询获取对应的数据
    #author__author_detail__city__startswith 就是join了author author_detail2张表,然后根据city为宁波开头的条件过滤出来获得bk对象
    #"title","publish__name"  bk对象有titile字段,可以直接获取,但是publish需要通过bk的publish_id去对应到Publish表查询,属于正向查询,按字段查询.
    bk = models.Book.objects.filter(author__author_detail__city__startswith="宁波").values("title","publish__name")
    print(bk) #QuerySet [{'title': 'java', 'publish__name': '南京出版社'}, {'title': 'python', 'publish__name': '北京出版社'}]>

    #还是查到城市以宁波开头的作者出版过的书籍和对应的出版社名字,这次以author为基表进行反向查询
    # author和author_detail有正向的连接的author_detail_id字段,所以filter直接筛选,获取到author对象
    # 接下来通过author对象获取book名和出版社名,但是author对象和book是反向查询关系,通过book表的title和book表下publish字段关联的Publish的name字段获取到最终结果.
    auth=models.Author.objects.filter(author_detail__city__startswith="宁波").values("book__title","book__publish__name")
    print(auth)

发表回复

您的电子邮箱地址不会被公开。