千家信息网

如何进行ORM多表操作

发表于:2025-01-26 作者:千家信息网编辑
千家信息网最后更新 2025年01月26日,本篇文章为大家展示了如何进行ORM多表操作,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。1.建表from django.db import models# C
千家信息网最后更新 2025年01月26日如何进行ORM多表操作

本篇文章为大家展示了如何进行ORM多表操作,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。

1.建表

from django.db import models# Create your models here.class AuthorDtail(models.Model):    nid = models.AutoField(primary_key=True)    birthday = models.DateField()    telephone = models.BigIntegerField()    addr = models.CharField(max_length=64)class Author(models.Model):    nid = models.AutoField(primary_key=True)    name = models.CharField(max_length=32)    age = models.IntegerField()    # OneToOneField可以建立在两个模型中的任意一个    authorDetail = models.OneToOneField(to="AuthorDtail", to_field="nid", on_delete=models.CASCADE)class Publish(models.Model):    nid = models.AutoField(primary_key=True)    name = models.CharField(max_length=32)    city = models.CharField(max_length=32)    email = models.EmailField()class Book(models.Model):    nid = models.AutoField(primary_key=True)    title = models.CharField(max_length=32)    publishDate = models.DateField()    price = models.DecimalField(max_digits=9,decimal_places=2)    # 与Publish建立一对多的关系,外键字段建立在多的一方    publish = models.ForeignKey(to="Publish", to_field="nid", on_delete=models.CASCADE)    # 多对多,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表    authors = models.ManyToManyField(to="Author")




MySQL查看建表语句

CREATE TABLE `app1_authordetail` (  `nid` int(11) NOT NULL AUTO_INCREMENT,  `birthday` date NOT NULL,  `telephone` bigint(20) NOT NULL,  `addr` varchar(64) NOT NULL,  PRIMARY KEY (`nid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;#UNIQUE KEY `authorDetail_id` (`authorDetail_id`),这是OneToOneField创建的。CREATE TABLE `app1_author` (  `nid` int(11) NOT NULL AUTO_INCREMENT,  `name` varchar(32) NOT NULL,  `age` int(11) NOT NULL,  `authorDetail_id` int(11) NOT NULL,  PRIMARY KEY (`nid`),  UNIQUE KEY `authorDetail_id` (`authorDetail_id`),  CONSTRAINT `app1_author_authorDetail_id_d894fd2a_fk_app1_authordetail_nid` FOREIGN KEY (`authorDetail_id`) REFERENCES `app1_authordetail` (`nid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;CREATE TABLE `app1_publish` (  `nid` int(11) NOT NULL AUTO_INCREMENT,  `name` varchar(32) NOT NULL,  `city` varchar(32) NOT NULL,  `email` varchar(254) NOT NULL,  PRIMARY KEY (`nid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;CREATE TABLE `app1_book` (  `nid` int(11) NOT NULL AUTO_INCREMENT,  `title` varchar(32) NOT NULL,  `publishDate` date NOT NULL,  `price` decimal(9,2) NOT NULL,  `publish_id` int(11) NOT NULL,  PRIMARY KEY (`nid`),  KEY `app1_book_publish_id_e41ee7e4` (`publish_id`),  CONSTRAINT `app1_book_publish_id_e41ee7e4_fk_app1_publish_nid` FOREIGN KEY (`publish_id`) REFERENCES `app1_publish` (`nid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;#ManyToManyField创建的第三方表CREATE TABLE `app1_book_authors` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `book_id` int(11) NOT NULL,  `author_id` int(11) NOT NULL,  PRIMARY KEY (`id`),  UNIQUE KEY `app1_book_authors_book_id_author_id_ce887e61_uniq` (`book_id`,`author_id`),  KEY `app1_book_authors_author_id_89b9ee26_fk_app1_author_nid` (`author_id`),  CONSTRAINT `app1_book_authors_author_id_89b9ee26_fk_app1_author_nid` FOREIGN KEY (`author_id`) REFERENCES `app1_author` (`nid`),  CONSTRAINT `app1_book_authors_book_id_75b281cd_fk_app1_book_nid` FOREIGN KEY (`book_id`) REFERENCES `app1_book` (`nid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1.表的名称是app_modelName,是根据模型中的元数据自动生成的,也可以重写为别的名称。2.如果没有定义AutoField(),默认会创建id字段,为主键。3.对于外键字段,Django会在字段上添加"_id"来设置列名。4.Django会根据settings中指定的数据库类型来使用相应的SQL语句。5.要在INSTALL_APPS中设置models.py所在的应用名称6.外键字段 ForeignKey 有一个 null=True 的设置(它允许外键接受空值 NULL),你可以赋给它空值 None 。

2.多表ORM的增删改查

2.1插入数据

2.1.1一对多插入数据

from django.shortcuts import renderfrom app1.models import *def index(request):    # 注意:这里一定要是一个model对象,不能是queryset对象    # 方式一:设置publish,是一个Model对象。    publish_obj = Publish.objects.get(nid=1)    aa_book_obj = Book.objects.create(title="AA_title",publishDate="2012-12-12",price=100,publish=publish_obj)    # 方式二:设置publish_id    bb_book_obj = Book.objects.create(title="BB_title", publishDate="2012-12-12", price=100, publish_id=2)    print(aa_book_obj.title)    print(aa_book_obj.publish.name)    print(bb_book_obj.title)    print(bb_book_obj.publish.name)    # 这里关键在于publish与publish_id的区别。    # 可以发现,    # publish是一个对象,可以通过publish调用相应Publish表中的字段数据    # publish_id只是Book表中的一个字段值    print(bb_book_obj.publish.nid)    print(bb_book_obj.publish_id)    return render(request, "index.html")
查询title为AA_title的出版社邮箱book_obj=Book.objects.filter(title="AA_title").first() print(book_obj.publish.email)

2.1.2多对多插入数据

from django.shortcuts import renderfrom app1.models import *def index(request):    # 绑定多对多关系    cc_book_obj = Book.objects.create(title="CC_title",publishDate="2018-12-12",price=120,publish_id=1)    vita = Author.objects.get(name="vita")    lili = Author.objects.get(name="lili")    # 方式一:add-author对象    cc_book_obj.authors.add(vita,lili)    # 方式二:add-author_id    dd_book_obj = Book.objects.create(title="DD_title",publishDate="2018-12-12",price=120,publish_id=1)    dd_book_obj.authors.add(1,2)    # 方式三:add-*[1,2,3]    ee_book_obj = Book.objects.create(title="EE_title", publishDate="2018-12-12", price=120, publish_id=1)    ee_book_obj.authors.add(*[1,2])    return render(request, "index.html")

2.1.3多对多的关键点

from django.shortcuts import renderfrom app1.models import *def index(request):    ee_book_obj = Book.objects.filter(title="EE_title").first()    # 关键点:ee_book_obj.authors.all()    # 与本书关联的所有作者信息集合,是queryset对象    # , ]>    print(ee_book_obj.authors.all())    return render(request, "index.html")

2.1.4多对多解除绑定

book_obj.authors.remove()      # 将某个特定的对象从被关联对象集合中去除。    ======   book_obj.authors.remove(*[])book_obj.authors.clear()       #清空被关联对象集合book_obj.authors.set()         #先清空再设置
from django.shortcuts import renderfrom app1.models import *def index(request):    vita = Author.objects.filter(name="vita").first()    aa_book_obj = Book.objects.filter(title="CC_title").first()    # 方式一:remove-author对象    aa_book_obj.authors.remove(vita)    # 方式二:remove-author的nid    aa_book_obj.authors.remove(2)    bb_book_obj = Book.objects.filter(title="DD_title").first()    # 方式三:remove-*[1,2]    bb_book_obj.authors.remove(*[1,2])    return render(request, "index.html")

2.2跨表查询

1 基于对象查询2 基于双下划线查询3 聚合和分组查询4 F 与 Q查询

2.2.1正向查询与反向查询

一对多关系中,models.ForeignKey设置在book中,根据book表查询author信息,是正向查询根据author表查询book信息,是反向查询多对多关系中,models.ManyToMany设置在book表中,根据book表查询author信息,是正向查询根据author表查询book信息,是反向查询一对一关系中,models.OneToOne设置在author表中,根据author表查询authoDetail信息,是正向查询根据authorDetail表查询quthor信息,是反向查询守则:正想查询按字段反向查询按表名详解:正向查询按字段,models.py中设置的关联字段,即Author类中的authorDetail,Book类中的publish和author。(一对多,多对多)反向查询按表名小写_set----因为是多个数据,所以使用set,集合之意。(一对一)反向查询按表名小写----因为只有一条对应数据,所以无set。

2.2.2基于对象查询----子查询

守则:正想查询按字段反向查询按表名详解:正向查询按字段,models.py中设置的关联字段,即Author类中的authorDetail,Book类中的publish和author。(一对多,多对多)反向查询按表名小写_set----因为是多个数据,所以使用set,集合之意。(一对一)反向查询按表名小写----因为只有一条对应数据,所以无set。
2.2.2.1准备数据




2.2.2.2基于对象查询--一对多查询
from django.shortcuts import renderfrom app1.models import *def index(request):    # 一对多的正向查询:查询三国演义这本书的出版社名字    # 一本书只对应一个出版社,返回值是一个model对象    publish_obj = Book.objects.filter(title="SanGuo").first().publish    print(publish_obj)  # Publish object (1)    print(publish_obj.name)  # AA出版社    # SQL语句:    # 一对多的反向查询:查询 AA_出版社 出版过的书籍名称    # 一个出版社对应多本书,返回值是一个queryset集合    book_list = Publish.objects.filter(name="AA_publish").first().book_set.all()    print(book_list)  # , , , ]>    # SQL语句:    return render(request, "index.html")

2.2.2.3基于对象查询--多对多查询
from django.shortcuts import renderfrom app1.models import *def index(request):    # 多对多正向查询:查询Sanguo这本书的所有作者名字    # 书和作者是多对多关系,返回值是queryset集合。    # , ]>    author_list = Book.objects.filter(title="SanGuo").first().authors.all()    print(author_list)    # 多对多反向查询:查询vita出版过的所有书籍名称    # 书和作者是多对多关系,返回值是queryset集合。    # , , , , ]>    book_list = Author.objects.filter(name="vita").first().book_set.all()    print(book_list)    return render(request, "index.html")

2.2.2.4基于对象查询--一对一查询
from django.shortcuts import renderfrom app1.models import *def index(request):    # 一对一的正向查询:查询vita的手机号    # 一对一关系,返回值是model对象    # AuthorDetail object (1)    author_detail_obj = Author.objects.filter(name="vita").first().authorDetail    print(author_detail_obj)    # 一对一的反向查询:查询手机号为112233的作者    # 一对一关系,返回值是model对象    # Author object (1)    author_obj = AuthorDetail.objects.filter(telephone="112233").first().author    print(author_obj)    return render(request, "index.html")

2.2.3基于双下划线的跨表查询----join查询

守则:正想查询按字段反向查询按表名
2.2.3.1基于双下划线的跨表查询--一对多查询
from django.shortcuts import renderfrom app1.models import *def index(request):    # 一对多查询:查询SanGuo这本书的出版社名字    # 返回值是queryset对象    # 方式一正向查询:    ret = Book.objects.filter(title="SanGuo").values("publish__name")    print(ret)  #     # 方式二反向查询:    ret2 = Publish.objects.filter(book__title="SanGuo").values("name")    print(ret2)  #     # 一对多查询:查询 AA_publish出版社出版的书籍名称    # 返回值是queryset对象    # 方式一正向查询:    ret3 = Publish.objects.filter(name="AA_publish").values("book__title")    print(ret3)  #     # 方式二反向查询:    ret4 = Book.objects.filter(publish__name="AA_publish").values("title")    print(ret4)  #     return render(request, "index.html")

2.2.3.2基于双下划线的跨表查询--多对多查询
from django.shortcuts import renderfrom app1.models import *def index(request):    # 多对多查询:查询SanGuo这本书的所有作者的名字    # 返回值:queryset对象    # 方式一:正向查询    ret1 = Book.objects.filter(title="SanGuo").values("authors__name")    print(ret1)  #     # 方式二:反向查询    ret2 = Author.objects.filter(book__title="SanGuo").values("name")    print(ret2)  #     return render(request, "index.html")

2.2.3.3基于双下划线的跨表查询--一对一查询
from django.shortcuts import renderfrom app1.models import *def index(request):    # 一对一查询:查询vita的手机号    # 返回值queryset对象    # 方式一:正向查询    ret1 = Author.objects.filter(name="vita").values("authorDetail__telephone")    print(ret1)  #     # 方式二:反向查询    ret2 = AuthorDetail.objects.filter(author__name="vita").values("telephone")    print(ret2)  #     return render(request, "index.html")

2.2.3.4基于双下划线的跨多表查询
from django.shortcuts import renderfrom app1.models import *def index(request):    # 手机号以11开头的作者出版过的书籍名称以及出版社的名称    ret1 = Author.objects.filter(authorDetail__telephone__startswith="11").values("book__title","book__publish__name")    print(ret1)    ret2 = AuthorDetail.objects.filter(telephone__startswith="11").values("author__book__title","author__book__publish__name")    print(ret2)    ret3 = Book.objects.filter(authors__authorDetail__telephone__startswith="11").values("title","publish__name")    print(ret3)    return render(request, "index.html")

2.2.4聚合与分组查询

2.2.4.1aggregate聚合查询
返回值是字典
from django.shortcuts import renderfrom django.db.models import Avg,Max,Min,Countfrom app1.models import *def index(request):    # 查询所有书籍的平均价格    # 返回值是字典    ret = Book.objects.filter(publishDate__year=2012).aggregate(avg_price=Avg("price"),max_price=Max("price"),min_price=Min("price"))    print(ret)  # {'avg_price': Decimal('100.000000'), 'max_price': Decimal('100.00'), 'min_price': Decimal('100.00')}    return render(request, "index.html")

2.2.4.2annotate分组查询--单表分组
# annotate分组查询# 单表分组查询的ORM语法: 单表模型.objects.values("group by的字段").annotate(聚合函数("统计字段"))# 返回值为queryset对象# 补充知识点:    #    # ret=Emp.objects.all()    # print(ret)  # select * from emp    # ret=Emp.objects.values("name")    # print(ret)  # select name from emp    # 单表下按照id分组,没有任何意义,这里all()就包含了所有字段,包含了主键id,id是唯一的,按照该字段分组没有任何意义    # Emp.objects.all().annotate(avg_salary=Avg("salary"))
from django.shortcuts import renderfrom django.db.models import Avg,Max,Min,Countfrom app1.models import *def index(request):    # 查询每种价格的书的价格和数量    # ret = Book.objects.values("price").annotate(book_count = Count("nid").values("title")    # 单表分组时,最后加values()是又加了一个分组字段,不是取出字段值    ret = Book.objects.values("price").annotate(book_count = Count("nid"))    print(ret)  #     return render(request, "index.html")

2.2.4.3annotate分组查询--多表分组
from django.shortcuts import renderfrom django.db.models import Avg,Max,Min,Countfrom app1.models import *def index(request):    # 查询每一个出版社的名称以及出版的书籍数    # 反向查询    ret1 = Publish.objects.values("name").annotate(book_count=Count("book__nid"))    print(ret1) #     # 正向查询    ret2 = Book.objects.values("publish__name").annotate(book_count=Count("nid"))    print(ret2) #     # 正向查询,最后values取值    ret3 = Book.objects.values("publish__nid").annotate(book_count=Count("nid")).values("publish__name","book_count")    print(ret3) #     return render(request, "index.html")

from django.shortcuts import renderfrom django.db.models import Avg,Max,Min,Countfrom app1.models import *def index(request):    # 总结 跨表的分组查询的模型:    # 每一个后表模型.objects.values("pk").annotate(聚合函数(关联表__统计字段))    # pk为主键    # 1.查询每一个作者的名字以及出版过的书籍的最高价格    ret1 = Author.objects.values("pk").annotate(max_price = Max("book__price")).values("name","max_price")    print(ret1)    # 2.查询每一个书籍的名称以及对应的作者数    ret2 = Book.objects.values("pk").annotate(author_count = Count("authors__nid")).values("title","author_count")    print(ret2)    return render(request, "index.html")

from django.shortcuts import renderfrom django.db.models import Avg,Max,Min,Countfrom app1.models import *def index(request):    # 查询每一个出版社的名称以及出版社的书籍个数    # 三种方式:    ret1=Publish.objects.values("nid").annotate(c=Count("book__title")).values("name","email","c")    print(ret1)    ret2=Publish.objects.all().annotate(c=Count("book__title")).values("name","c","city")    print(ret2)    ret3 = Publish.objects.annotate(c=Count("book__title")).values("name", "c", "city")    print(ret3)    return render(request, "index.html")

from django.shortcuts import renderfrom django.db.models import Avg,Max,Min,Countfrom app1.models import *def index(request):    # 统计每一本以S开头的书籍的作者个数    ret1 = Book.objects.filter(title__startswith="S").values("pk").annotate(author_count = Count("authors__nid")).values("title","author_count")    print(ret1)    # 统计不止一个作者的图书    ret2 = Book.objects.values("pk").annotate(author_count = Count("authors__nid")).filter(author_count__gt=1).values("title","author_count")    print(ret2)    return render(request, "index.html")

2.2.5F查询与Q查询

2.2.5.1F查询
from django.shortcuts import renderfrom django.db.models import F,Qfrom app1.models import *def index(request):    # 1.F查询,两个字段值作比较    ret1 = Book.objects.filter(price__gt=F("publish_id"))    print(ret1)    # 2.F查询与常数之间的加减乘除和取模    ret2 = Book.objects.filter(price__gt=F("publish_id")*100)    print(ret2)    # 3.支持批量更新    Book.objects.all().update(price=F("price")+30)    return render(request, "index.html")

2.2.5.2Q查询
from django.shortcuts import renderfrom django.db.models import F,Qfrom app1.models import *def index(request):    # 1.Q查询可以用于"或"查询,filter()方法是"and"查询    ret1 =Book.objects.filter(Q(authors__name="vita")|Q(authors__name="lili"))    print(ret1)    # 2.可以组合&和|以及~(取反)    # 作者名是vita,age!=23    ret2 = Book.objects.filter(Q(authors__name="vita")&~Q(authors__age=23))    print(ret2)    # 3.查询函数可以混合使用Q对象和关键字参数。关键字参数要放在最后面    ret3 = Book.objects.filter(Q(authors__age=23)|Q(publishDate__year=2012),title__startswith="S")    print(ret3)    return render(request, "index.html")

上述内容就是如何进行ORM多表操作,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注行业资讯频道。

0