本篇文章为大家展示了如何进行对象关系映射(对象关系映射)多表操作,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。
1.建表
来自django。dbimportmodels
#在此创建您的模型。
classAuthorDtail(模型。型号):
nid=模型。自动字段(主键=真)
生日=模特。日期字段()
电话=型号BigIntegerField()
addr=模型。字符字段(最大长度=64)
类作者(模型。型号):
nid=模型。自动字段(主键=真)
名称=型号。字符字段(最大长度=32)
年龄=模特英特尔场()
#一个字段可以建立在两个模型中的任意一个
authorDetail=模型一个toonefield(to=' Authordail ',to_field='nid ',on_delete=models .CASCADE)
类发布(模型。型号):
nid=模型。自动字段(主键=真)
名称=型号。字符字段(最大长度=32)
城市=模型。字符字段(最大长度=32)
电子邮件=模型EmailField()
classBook(模型。型号):
nid=模型。自动字段(主键=真)
标题=模型。字符字段(最大长度=32)
发布日期=模型。日期字段()
价格=型号。十进制字段(最大位数=9,小数位数=2)
#与出版建立一对多的关系,外键字段建立在多的一方
发布=模型ForeignKey(to='Publish ',to_field='nid ',on_delete=models .CASCADE)
#多对多,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表
作者=模型。曼托马尼菲尔德(致='作者)
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 render from 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 render from 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 render from app1.models import * def index(request): ee_book_obj = Book.objects.filter(title="EE_title").first() # 关键点:ee_book_obj.authors.all() # 与本书关联的所有作者信息集合,是queryset对象 # <QuerySet [<Author: Author object (1)>, <Author: Author object (2)>]> 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 render from 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 render from 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) # <QuerySet [<Book: Book object (7)>, <Book: Book object (9)>, <Book: Book object (10)>, <Book: Book object (11)>]> # SQL语句: return render(request, "index.html")
2.2.2.3基于对象查询--多对多查询
from django.shortcuts import render from app1.models import * def index(request): # 多对多正向查询:查询Sanguo这本书的所有作者名字 # 书和作者是多对多关系,返回值是queryset集合。 # <QuerySet [<Author: Author object (1)>, <Author: Author object (2)>]> author_list = Book.objects.filter(title="SanGuo").first().authors.all() print(author_list) # 多对多反向查询:查询vita出版过的所有书籍名称 # 书和作者是多对多关系,返回值是queryset集合。 # <QuerySet [<Book: Book object (7)>, <Book: Book object (8)>, <Book: Book object (9)>, <Book: Book object (10)>, <Book: Book object (11)>]> 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 render from 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 render from app1.models import * def index(request): # 一对多查询:查询SanGuo这本书的出版社名字 # 返回值是queryset对象 # 方式一正向查询: ret = Book.objects.filter(title="SanGuo").values("publish__name") print(ret) # <QuerySet [{'publish__name': 'AA_publish'}]> # 方式二反向查询: ret2 = Publish.objects.filter(book__title="SanGuo").values("name") print(ret2) # <QuerySet [{'name': 'AA_publish'}]> # 一对多查询:查询 AA_publish出版社出版的书籍名称 # 返回值是queryset对象 # 方式一正向查询: ret3 = Publish.objects.filter(name="AA_publish").values("book__title") print(ret3) # <QuerySet [{'book__title': 'SanGuo'}, {'book__title': 'HongLou'}, {'book__title': 'XiYou'}, {'book__title': 'XiaoWangZi'}]> # 方式二反向查询: ret4 = Book.objects.filter(publish__name="AA_publish").values("title") print(ret4) # <QuerySet [{'title': 'SanGuo'}, {'title': 'HongLou'}, {'title': 'XiYou'}, {'title': 'XiaoWangZi'}]> return render(request, "index.html")
2.2.3.2基于双下划线的跨表查询--多对多查询
from django.shortcuts import render from app1.models import * def index(request): # 多对多查询:查询SanGuo这本书的所有作者的名字 # 返回值:queryset对象 # 方式一:正向查询 ret1 = Book.objects.filter(title="SanGuo").values("authors__name") print(ret1) # <QuerySet [{'authors__name': 'vita'}, {'authors__name': 'lili'}]> # 方式二:反向查询 ret2 = Author.objects.filter(book__title="SanGuo").values("name") print(ret2) # <QuerySet [{'name': 'vita'}, {'name': 'lili'}]> return render(request, "index.html")
2.2.3.3基于双下划线的跨表查询--一对一查询
from django.shortcuts import render from app1.models import * def index(request): # 一对一查询:查询vita的手机号 # 返回值queryset对象 # 方式一:正向查询 ret1 = Author.objects.filter(name="vita").values("authorDetail__telephone") print(ret1) # <QuerySet [{'authorDetail__telephone': 112233}]> # 方式二:反向查询 ret2 = AuthorDetail.objects.filter(author__name="vita").values("telephone") print(ret2) # <QuerySet [{'telephone': 112233}]> return render(request, "index.html")
2.2.3.4基于双下划线的跨多表查询
from django.shortcuts import render from 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 render from django.db.models import Avg,Max,Min,Count from 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 render from django.db.models import Avg,Max,Min,Count from 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) # <QuerySet [{'price': Decimal('100.00'), 'book_count': 2}, {'price': Decimal('120.00'), 'book_count': 3}]> return render(request, "index.html")
2.2.4.3annotate分组查询--多表分组
from django.shortcuts import render from django.db.models import Avg,Max,Min,Count from app1.models import * def index(request): # 查询每一个出版社的名称以及出版的书籍数 # 反向查询 ret1 = Publish.objects.values("name").annotate(book_count=Count("book__nid")) print(ret1) # <QuerySet [{'name': 'AA_publish', 'book_count': 4}, {'name': 'BB_publish', 'book_count': 1}]> # 正向查询 ret2 = Book.objects.values("publish__name").annotate(book_count=Count("nid")) print(ret2) # <QuerySet [{'publish__name': 'AA_publish', 'book_count': 4}, {'publish__name': 'BB_publish', 'book_count': 1}]> # 正向查询,最后values取值 ret3 = Book.objects.values("publish__nid").annotate(book_count=Count("nid")).values("publish__name","book_count") print(ret3) # <QuerySet [{'publish__name': 'AA_publish', 'book_count': 4}, {'publish__name': 'BB_publish', 'book_count': 1}]> return render(request, "index.html")
from django.shortcuts import render from django.db.models import Avg,Max,Min,Count from 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 render from django.db.models import Avg,Max,Min,Count from 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 render from django.db.models import Avg,Max,Min,Count from 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 render from django.db.models import F,Q from 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 render from django.db.models import F,Q from 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多表操作,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注行业资讯频道。
内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/117462.html