DjangoORM多表实例
Posted 礁之
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DjangoORM多表实例相关的知识,希望对你有一定的参考价值。
文章目录
此文章参考菜鸟教程:Django ORM – 多表实例 | 菜鸟教程 (runoob.com)
Django版本:
>>> django.VERSION
(4, 1, 0, 'final', 0)
PS:基于前几章的进度进行修改
一、Django ORM 多表实例
- 表与表之间的关系可以分为以下三种:
一对一
:一个人对应一个的身份证号,数据字段设置为unique一对多
:一个家庭有多个人,一般通过外键来实现多对多
:一个学生有多门课程,一个课程有很多学生,一般通过第三个表来实现关联
- 下面是菜鸟的示例图
创建模型
- 修改
app1/app1_model/models.py
# -*- coding: utf-8 -*-
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");
# 先插入 authordetail 表中多数据
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");
# 再将数据插入 author,这样 author 才能找到 authordetail
insert into app1_model_author(name,age,au_detail_id) values ("令狐冲",25,1),("任我行",58,2),("任盈盈",23,3);
- 执行
二、ORM 插入数据
一对多—外键 ForeignKey
方式一:传输对象的形式,返回值的数据类型是对象,即书籍对象
- 具体步骤:
- 获取出版社对象
- 给书籍的出版社属性
pulish
传入出版社对象
- 修改app1/app1/views.py文件
# -*- coding: utf-8 -*-
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
#books = models.Book.objects.create(title="Python",price=500,publish="Python出版社",pub_date="1970-12-10")
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文件
# -*- coding: utf-8 -*-
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
#books = models.Book.objects.create(title="Python",price=500,publish="Python出版社",pub_date="1970-12-10")
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文件
# -*- coding: utf-8 -*-
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
#books = models.Book.objects.create(title="Python",price=500,publish="Python出版社",pub_date="1970-12-10")
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
# -*- coding: utf-8 -*-
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
#books = models.Book.objects.create(title="Python",price=500,publish="Python出版社",pub_date="1970-12-10")
#chong = models.Author.objects.filter(name="令狐冲").first()
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的方式
*[]
的使用,下面是传入对象的方式
# -*- coding: utf-8 -*-
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
#books = models.Book.objects.create(title="Python",price=500,publish="Python出版社",pub_date="1970-12-10")
book_obj = models.Book.objects.get(id=2)
author_list = models.Author.objects.filter(id__gt=2)
book_obj.authors.add(*author_list) #将id大于2的作者对象添加到这本书的作者集合中
return HttpResponse("ok")
- 访问测试
- 查看数据库信息,可以发现id为2的书籍,作者对象的id都是大于2的,即id为2和3的作者
- 传入对象id的方式
# -*- coding: utf-8 -*-
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
#books = models.Book.objects.create(title="Python",price=500,publish="Python出版社",pub_date="1970-12-10")
book_obj = models.Book.objects.get(id=2)
#author_list = models.Author.objects.filter(id__gt=2)
book_obj.authors.add(*[1,3]) #将id为1和3的作者添加到这本书作者的集合中
return HttpResponse("ok")
- 访问测试
- 查看数据库信息,可以发现id为2的书籍,3个作者都已经添加到了集合中
- 下面是反向,反向应该是
小写表面_set
# -*- coding: utf-8 -*-
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
#books = models.Book.objects.create(title="Python",price=500,publish="Python出版社",pub_date="1970-12-10")
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()
- 创建一个新的对象,并且同时将它添加到关联对象集之中,返回新创建的对象
# -*- coding: utf-8 -*-
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
#books = models.Book.objects.create(title="Python",price=500,publish="Python出版社",pub_date="1970-12-10")
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
即可以为空时存在,没有返回值 - 先来看一下数据库信息,确定好要删除的行
- 例如要删除书籍2和作者2的行
# -*- coding: utf-8 -*-
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
#books = models.Book.objects.create(title="Python",price=500,publish="Python出版社",pub_date="1970-12-10")
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
即可以为空时存在,没有返回值
# -*- coding: utf-8 -*-
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
#books = models.Book.objects.create(title="Python",price=500,publish="Python出版社",pub_date="1970-12-10")
book = models.Book.objects.filter(title="Django教程").first()
book.authors.clear() #删除django教程的所有关联
return HttpResponse("ok")
- 访问测试
- 查看数据库信息,可以看到
Book
表中的Django教程行还是存在的,但是关联表book_authors
中的Django教程(id=2)
的行已经被删除
四、ORM查询
-
基于对象的跨表查询
-
语法:
正向:属性名称
反向:小写类名_set
1、一对多
- 查询主键为3的书籍出版社所在的城市,即正向查询
# -*- coding: utf-8 -*-
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
#books = models.Book.objects.create(title="Python",price=500,publish="Python出版社",pub_date="1970-12-10")
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
对象中,遍历取出书籍对象
# -*- coding: utf-8 -*-
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
#books = models.Book.objects.create(title="Python",price=500,publish="Python出版社",pub_date="1970-12-10")
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)可以跳转到关联的表
- 下面查询令狐冲的电话
# -*- coding: utf-8 -*-
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
#books = models.Book.objects.create(title="Python",price=500,publish="Python出版社",pub_date="1970-12-10")
author = models.Author.objects.filter(name="令狐冲").first()
res = author.au_detail.tel
print(res,type(res))
return HttpResponse("ok")
- 访问测试
- 查看终端输出和数据库信息
- 查询到所有住址在黑木崖的作者姓名,即反向,一对一的反向,使用
对象.小写类名
即可,不用加_set
- 反向:
对象.小写类名(addr.author)
可以跳转到关联的表
# -*- coding: utf-8 -*-
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
#books = models.Book.objects.create(title="Python",price=500,publish="Python出版社",pub_date="1970-12-10")
addr = models.AuthorDetail.objects.filter(addr="黑木崖").first()
res = addr.author.name
print(res,type(res))
return HttpResponse("ok")
- 访问测试
- 查看终端输出和数据库信息,由于上面查询时使用了
first()
方法,所以只输出了一个作者名称
3、多对多
-
正向:
对象.属性(book.authors)
可以跳转到关联的表 -
下面寻找Python教程的所有作者以及手机号,即正向,由于作者表里并没有手机号,所以还需要通过
对象.属性(i.au_detail)
跳转到关联的表
# -*- coding: utf-8 -*-
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
#books = models.Book.objects.create(title="Python",price=500,publish="Python出版社",pub_date="1970-12-10")
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")
- 访问测试
- 查看终端输出和数据库信息
- 下面查询任我行写的所有书籍的名称,即反向
# -*- coding: utf-8 -*-
from django.shortcuts import render,HttpResponse
from app1_model import models
def add_book(request):
#books = models.Book.objects.create(title="Python",price=500,publish="Python出版社",pub_date="1970-12-10")
author = models.Author.objects以上是关于DjangoORM多表实例的主要内容,如果未能解决你的问题,请参考以下文章
薅羊毛啦! 价值$1000动态规划答疑讲堂, 令狐冲老师为您划重点!
1$答疑讲堂 | 令狐冲现场剖析如何学好动态规划,为你解答疑惑