文章目录
- 一、Django ORM 多表实例
-
- 二、ORM 插入数据
- 一对多—外键 ForeignKey
- 多对多(Many ToManyField):在第三张表添加数据
- 三、关联管理器——对象调用
- 1、add()
- 2、create()
- 3、remove()
- 4、clear()
- 四、ORM查询
-
- 五、基于双下划线的跨表查询
-
此文章参考菜鸟教程:Django ORM – 多表实例 | 菜鸟教程 (runoob.com)
Django版本:
>>> django.VERSION
(4, 1, 0, 'final', 0)
PS:基于前几章的进度进行修改
一、Django ORM 多表实例
一对一
:一个人对应一个的身份证号,数据字段设置为unique一对多
:一个家庭有多个人,一般通过外键来实现多对多
:一个学生有多门课程,一个课程有很多学生,一般通过第三个表来实现关联
- 下面是菜鸟的示例图
创建模型
- 修改
app1/app1_model/models.py
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=5,decimal_places=2)
pub_date = models.DateField()
publish = models.ForeignKey("Publish",on_delete=models.CASCADE)
authors = models.ManyToManyField("Author")
class Publish(models.Model):
name = models.CharField(max_length=32)
city = models.CharField(max_length=64)
email = models.EmailField()
class Author(models.Model):
name = models.CharField(max_length=32)
age = models.SmallIntegerField()
au_detail = models.OneToOneField("AuthorDetail",on_delete=models.CASCADE)
class AuthorDetail(models.Model):
gender_choices = (
(0,"女"),
(1,"男"),
(2,"保密"),
)
gender = models.SmallIntegerField(choices=gender_choices)
tel = models.CharField(max_length=32)
addr = models.CharField(max_length=64)
birthday = models.DateField()
EmailField
数据类型是邮箱格式,底层继承CharField
进行了封装,相当于Mysql中的varchar
- 一般不需要级联更新
- 如果有
模型类
存在外键,在创建数据时,需要先创建外键关联的模型类数据,否则在创建包含外键的模型类数据时,外键的关联模型类数据会找不到
-
设置一对一OneToOneField = ForeignKey("关联类名",unique=True)
-
外键在一对多中设置,即models.ForeignKey("关联类名",on_delete=models.CASCADE)
,后面是设置外键删除时的操作:
CASCADE:
默认选项,表示级联删除PROTECT:
保护模式,使用该选项,在删除时,会抛出ProtectedError
的错误SET_NULL:
置空模式,删除时,外键字段被设置为空,前提是blank=True
、null=True
,定义该字段时,需要外键允许为空SET_DEFAULT:
删除时,外键字段设置为默认值
,使用该选项时,需要注意外键的上一个默认值SET( ):
括号里可以是函数,设置自定义的值DO_NOTHING:
什么也不做
(test) PS F:\django\app1> python .\manage.py makemigrations app1_model
Migrations for 'app1_model':
app1_model\migrations\0002_authordetail_publish_alter_book_id_author_and_more.py
- Create model AuthorDetail
- Create model Publish
- Alter field id on book
- Create model Author
- Add field authors to book
- Alter field publish on book
(test) PS F:\django\app1> python .\manage.py migrate app1_model
Operations to perform:
Apply all migrations: app1_model
Running migrations:
Applying app1_model.0002_authordetail_publish_alter_book_id_author_and_more... OK
- 查看mysql数据库,可以看到有一个
app1_model_book_authors
这个就是多对多的第三张表
插入数据
insert into app1_model_publish(name,city,email) values ("华山出版社","华山","hs@163.com"),("明教出版社","黑木崖","mj@163.com");
insert into app1_model_authordetail(gender,tel,addr,birthday) values (1,13432335433,"华山","1994-5-23"),(1,13943454554,"黑木崖","1961-8-13"),(0,13878934322,"黑木崖","1996-5-20");
insert into app1_model_author(name,age,au_detail_id) values ("令狐冲",25,1),("任我行",58,2),("任盈盈",23,3);
二、ORM 插入数据
一对多—外键 ForeignKey
方式一:传输对象的形式,返回值的数据类型是对象,即书籍对象
- 获取出版社对象
- 给书籍的出版社属性
pulish
传入出版社对象
- 修改app1/app1/views.py文件
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
pub_obj = models.Publish.objects.filter(pk=1).first()
book = models.Book.objects.create(title="Python教程",price=200,pub_date="2011-11-11",publish=pub_obj)
print(book,type(book))
return HttpResponse(book)
- 访问
127.0.0.1:8000/add_book
方式二:传入对象id的形式
- 由于传过来的数据一般都是id,所以传入对象id是比较常用的
- 在一对多中,设置外键属性的类中,即指
多
的表,Mysql中显示的字段名称是外键属性名_id
,返回值的数据类型是对象,即书籍对象 - 步骤:
- 获取出版社对象的id
- 给书籍的关联出版社字段
pulish_id
传入出``版社对象的id`
- 修改app1/app1/views.py文件
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
pub_obj = models.Publish.objects.filter(pk=1).first()
pk = pub_obj.pk
book = models.Book.objects.create(title="Django教程",price=100,pub_date="2012-12-12",publish_id=pk)
print(book,type(book))
return HttpResponse(book)
多对多(Many ToManyField):在第三张表添加数据
方式一:传入对象形式,没有返回值
- 获取作者对象
- 获取书籍对象
- 给书籍对象的
authors
属性用add
的方法纯如作者对象
- 修改app1/app1/views.py文件
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
chong = models.Author.objects.filter(name="令狐冲").first()
book = models.Book.objects.filter(title="Python教程").first()
book.authors.add(chong)
return HttpResponse(book)
- 访问
127.0.0.1:8000/add_book
进行测试
方式二:传入对象id形式,没有返回值
- 获取作者对象的id
- 获取书籍对象
- 给书籍对象的
authors
属性使用add
的方法传入作者的id
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
xing = models.Author.objects.filter(name="任我行").filter()
for i in xing:
print(i.pk)
book = models.Book.objects.filter(title="Django教程").first()
book.authors.add(i.pk)
return HttpResponse(xing)
- 访问
127.0.0.1:8000/add_book
进行测试
三、关联管理器——对象调用
多对多:需要双向均有关联管理器
一对多:只有多的那个类的对象需要关联管理器,也就是只有反向才有
注意:一对多只能反向
正向:属性名称
反向:小写类名+_set
1、add()
add()
主要用于多对多,把指定的模型对象添加到关联对象集(对象表)中
注意:add()在一对多,即外键中,只能通过传入对象的方式不能通过传入id的方式
*[]
的使用,下面是传入对象的方式
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
book_obj = models.Book.objects.get(id=2)
author_list = models.Author.objects.filter(id__gt=2)
book_obj.authors.add(*author_list)
return HttpResponse("ok")
- 查看数据库信息,可以发现id为2的书籍,作者对象的id都是大于2的,即id为2和3的作者
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
book_obj = models.Book.objects.get(id=2)
book_obj.authors.add(*[1,3])
return HttpResponse("ok")
- 查看数据库信息,可以发现id为2的书籍,3个作者都已经添加到了集合中
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
ying = models.Author.objects.filter(name="任盈盈").first()
book = models.Book.objects.filter(title="Python教程").first()
ying.book_set.add(book)
return HttpResponse("ok")
- 查看数据库信息,可以看到
Python教程(id=1)
数据的作者添加了任盈盈(id=3)
2、create()
- 创建一个新的对象,并且同时将它添加到关联对象集之中,返回新创建的对象
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
pub = models.Publish.objects.filter(name="明教出版社").first()
wo = models.Author.objects.filter(name="任我行").first()
book = wo.book_set.create(title="ORM教程",price=150,pub_date="2012-10-10",publish=pub)
print(book,type(book))
return HttpResponse("ok")
3、remove()
- 从关联对象集中移除执行的对象,对于
ForeignKey
对象,这个方法尽在null=True
即可以为空时存在,没有返回值 - 先来看一下数据库信息,确定好要删除的行
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
author_obj = models.Author.objects.get(id=2)
book_obj = models.Book.objects.get(id=2)
author_obj.book_set.remove(book_obj)
return HttpResponse("ok")
- 查看数据库信息,可以看到已经删除
4、clear()
- 从关联对象集合中移除
所有
对象,删除关联,不会删除对象。对于ForeignKey
对象,这个方法仅在null=True
即可以为空时存在,没有返回值
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
book = models.Book.objects.filter(title="Django教程").first()
book.authors.clear()
return HttpResponse("ok")
- 查看数据库信息,可以看到
Book
表中的Django教程行还是存在的,但是关联表book_authors
中的Django教程(id=2)
的行已经被删除
四、ORM查询
正向:属性名称
反向:小写类名_set
1、一对多
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
book = models.Book.objects.filter(pk=3).first()
res = book.publish.city
print(res,type(res))
return HttpResponse("ok")
-
访问测试
-
查看终端输出和数据库信息,可以看到是相同的
- 查询华山出版社出版的书籍名称,即反向
- 反向的写法:
对象.小写类名_set(pub.book_set)
可以跳转到关联的表,即书籍表 pub.book_set.all()
:取出书籍表中的所有书籍对象,在一个QuerySet
对象中,遍历取出书籍对象
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
pub = models.Publish.objects.filter(name="华山出版社").first()
res = pub.book_set.all()
for i in res:
print(i.title)
return HttpResponse("ok")
-
访问测试
-
查看终端输出和数据库信息
2、一对一
- 正向:对象.属性(author.au_detail)可以跳转到关联的表
- 下面查询令狐冲的电话
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
author = models.Author.objects.filter(name="令狐冲").first()
res = author.au_detail.tel
print(res,type(res))
return HttpResponse("ok")
- 查询到所有住址在黑木崖的作者姓名,即反向,一对一的反向,使用
对象.小写类名
即可,不用加_set
- 反向:
对象.小写类名(addr.author)
可以跳转到关联的表
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
addr = models.AuthorDetail.objects.filter(addr="黑木崖").first()
res = addr.author.name
print(res,type(res))
return HttpResponse("ok")
- 查看终端输出和数据库信息,由于上面查询时使用了
first()
方法,所以只输出了一个作者名称
3、多对多
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
book = models.Book.objects.filter(title="Python教程").first()
res = book.authors.all()
for i in res:
print(i.name,i.au_detail.tel)
return HttpResponse("ok")
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
author = models.Author.objects.filter(name="任我行").first()
res = author.book_set.all()
for i in res:
print(i.title)
return HttpResponse("ok")
五、基于双下划线的跨表查询
- 正向:
属性名称__跨表的属性名称
- 反向:
小写类名__跨表的属性名称
1、一对多
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
res = models.Book.objects.filter(publish__name="华山出版社").values_list("title","price")
return HttpResponse(res)
- 下面是反向,通过
小写类名__跨表的属性名称(book__title,book__price)
跨表获取数据
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
res = models.Publish.objects.filter(name="华山出版社").values_list("book__title","book__price")
return HttpResponse(res)
- 访问测试
2、多对多
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
res = models.Book.objects.filter(authors__name="任我行").values_list("title")
return HttpResponse(res)
- 反向:通过
小写类名__跨表的属性名称(book__title)
跨表获取数据
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
res = models.Author.objects.filter(name="任我行").values_list("book__title")
return HttpResponse(res)
3、一对一
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
res = models.Author.objects.filter(name="任我行").values_list("au_detail__tel")
return HttpResponse(res)
- 反向:通过
小写类名__跨表的属性名称(author__name)
跨表获取数据
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
res = models.AuthorDetail.objects.filter(author__name="任我行").values_list("tel")
return HttpResponse(res)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)