Django 学习 之ORM多表操作
一.创建模型
1.模型关系整理
创建一对一的关系:OneToOne("要绑定关系的表名")
创建一对多的关系:ForeignKey("要绑定关系的表名")
创建多对多的关系:ManyToMany("要绑定关系的表名") 会自动创建第三张表
书籍模型: 书籍有书名和出版日期,一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to-many);
一本书只应该由一个出版商出版,所以出版商和书籍是一对多关联关系(one-to-many)。
一对一、多对一、多对多 ,用book表和publish表自己来想想关系,想想里面的操作,加外键约束和不加外键约束的区别,一对一的外键约束是在一对多的约束上加上唯一约束。
实例:我们来假定下面这些概念,字段和关系
作者模型:一个作者有姓名和年龄。
作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息。作者详情模型和作者模型之间是一对一的关系(one-to-one)
出版商模型:出版商有名称,所在城市以及email。
书籍模型: 书籍有书名和出版日期,一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to-many);一本书只应该由一个出版商出版,所以出版商和书籍是一对多关联关系(one-to-many)。
下面我们通过图书管理系统,来设计出每张表之间的对应关系。
通过上图关系,来定义一下我们的模型类。
2.模型关系类的编写
from django.db import models
class Book(models.Model):
# nid = models.AutoField(primary_key=True) # 自增id(可以不写,默认会有自增id)
title = models.CharField(max_length=32) # 书名
price = models.DecimalField(max_digits=5, decimal_places=2)
# 价格 一共5位,保留两位小数
pub_date = models.DateField() #出版日期
# 一个出版社有多本书,关联字段要写在多的一方
# 不用命名为publish_id,因为django为我们自动就加上了_id
# foreignkey(表名)建立的一对多关系
publish = models.ForeignKey("Publish", on_delete=models.CASCADE)
authors = models.ManyToManyField("Author") # 建立的多对多的关系
class Publish(models.Model):
# 不写id的时候数据库会自动给你增加自增id
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()
3.注意事项
1、 表的名称myapp_modelName,是根据 模型中的元数据自动生成的,也可以覆写为别的名称
2、id 字段是自动添加的
3、对于外键字段,Django 会在字段名上添加"_id" 来创建数据库中的列名
4、这个例子中的CREATE TABLE SQL 语句使用MySQL 语法格式,要注意的是Django 会根据settings 中指定的数据库类型来使用相应的SQL 语句。
5、定义好模型之后,你需要告诉Django _使用_这些模型。你要做的就是修改配置文件中的INSTALL_APPSZ中设置,在其中添加models.py所在应用的名称。
6、外键字段 ForeignKey 有一个 null=True 的设置(它允许外键接受空值 NULL),你可以赋给它空值 None 。
4.关于字段选项
每个字段有一些特有的参数,例如,CharField需要max_length参数来指定VARCHAR数据库字段的大小。还有一些适用于所有字段的通用参数。 这些参数在文档中有详细定义,这里我们只简单介绍一些最常用的:
1)null
如果为True,Django 将用NULL 来在数据库中存储空值。 默认值是 False.
(1)blank
如果为True,该字段允许不填。默认为False。
要注意,这与 null 不同。null纯粹是数据库范畴的,而 blank 是数据验证范畴的。
如果一个字段的blank=True,表单的验证将允许该字段是空值。如果字段的blank=False,该字段就是必填的。
(2)default
字段的默认值。可以是一个值或者可调用对象。如果可调用 ,每有新对象被创建它都会被调用。
(3)primary_key
如果为True,那么这个字段就是模型的主键。如果你没有指定任何一个字段的primary_key=True,
Django 就会自动添加一个IntegerField字段做为主键,所以除非你想覆盖默认的主键行为,
否则没必要设置任何一个字段的primary_key=True。
(4)unique
如果该值设置为 True, 这个数据字段的值在整张表中必须是唯一的
(5)choices
由二元组组成的一个可迭代对象(例如,列表或元组),用来给字段提供选择项。 如果设置了choices ,
默认的表单将是一个选择框而不是标准的文本框,而且这个选择框的选项就是choices 中的选项。
这是一个关于 choices 列表的例子:
YEAR_IN_SCHOOL_CHOICES = (
('FR', 'Freshman'),
('SO', 'Sophomore'),
('JR', 'Junior'),
('SR', 'Senior'),
('GR', 'Graduate'),
)
每个元组中的第一个元素,是存储在数据库中的值;第二个元素是在管理界面或 ModelChoiceField 中用作显示的内容。
在一个给定的 model 类的实例中,想得到某个 choices 字段的显示值,就调用 get_FOO_display 方法(这里的 FOO 就是 choices 字段的名称 )。例如:
from django.db import models
class Person(models.Model):
SHIRT_SIZES = (
('S', 'Small'),
('M', 'Medium'),
('L', 'Large'),
)
name = models.CharField(max_length=60)
shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES)
>>> p = Person(name="Fred Flintstone", shirt_size="L")
>>> p.save()
>>> p.shirt_size
'L'
>>> p.get_shirt_size_display()
'Large
一旦你建立好数据模型之后,django会自动生成一套数据库抽象的API,可以让你执行关于表记录的增删改查的操作。
二.操作表记录
1.添加一些简单的数据
(1)publish表
insert into app01_publish(name,city,email) values("华山出版社", "华山", "hs@163.com"), ("明教出版社", "黑木崖", "mj@163.com");
(2)authordatail表
insert into app01_authordetail(gender,tel,addr,birthday) value (1,13432335433,"华山","1994-5-23"),(1,13943454554,"黑木崖","1961-8-13"),(0,13878934322,"黑木崖","1996-5-20");
(3)author表
insert into app01_author(name,age,au_detail_id) value ("令狐冲",25,1),("任我行",58,2),("任盈盈",23,3);
多表存在关联的情况下,插入数据需要先将被关联的表的数据先插入,在插入关联的表的数据。
2.一对多添加记录
# 一对多的添加
# 方式一:如果是这样直接指定publish_id字段去添加值,前提是你的主表里面必须有数据
# 主表:没有被关联的(因为book表是要依赖于publish这个表的)也就是publish表
# 子表:关联的表
# ##一对多新增
# 方式一 传对象的形式
pub_obj = models.Publish.objects.get(pk=1)
book = models.Book.objects.create(title="独孤九剑", price=180, pub_date="2018-10-23", publish=pub_obj)
# 方式二 传对象的id(用的更多)
# new_book = models.Book.objects.create(title="冲灵剑法", price=120, pub_date="2018-08-23", publish_id=pub_obj.pk)
# print(new_book)
3.多对多
# ##多对多新增
# 方式一 传对象的形式
# book_obj = models.Book.objects.get(pk=1)
# print(book_obj)
# ling = models.Author.objects.get(pk=1)
# print(ling)
# ying = models.Author.objects.get(pk=3)
# print(ying)
# book_obj.authors.add(ling, ying)
# 传入的是对象,通过模型会自动转为相应的id,为book_authors新增信息
#
# # 方式二 传对象id
book_obj = models.Book.objects.get(pk=2)
ling = models.Author.objects.get(pk=1)
# print(ling.pk)
book_obj.authors.add(ling.pk)
book_obj.authors.remove() # 将某个特定的对象从被关联对象集合中去除。 ====== book_obj.authors.remove(*[])
book_obj.authors.clear() #清空被关联对象集合
book_obj.authors.set() #先清空再设置
总结:remove和clear的区别
remove:得吧你要清除的数据筛选出来,然后移除
clear:不用查,直接就把数据都清空了。
各有应用场景
关于关联管理器大前提:
(1)多对多,双向都有
(2)一对多时,对应多的一方才有(出版社的角度)
(3)一对多时,反向才能使用关联管理器
正向按字段名
反向按小写表名+ _set
4.基于对象的跨表查询
"""
正向: 字段名称
---------------->
Book Publish
<----------------
反向: 小写表名+_set
"""
(1)一对多查询(Publish 与 Book)
# 正向例子
# 查询主键为1的书籍的出版社所在的城市
book_obj = models.Book.objects.get(pk=1)
print(book_obj.publish.city)
# 反向例子
# 查询华山出版社出版的书籍名
pub_obj = models.Publish.objects.filter(name="华山出版社").first()
# 反向获取到存在这个pub_obj对象的书,在遍历出来
for book in pub_obj.book_set.all():
print(book.title)
(2)一对一查询(Author 和 AuthorDetail)
正向查询(按字段:au_detail)
# 查询令狐冲的电话
author_obj = models.Author.objects.filter(name="令狐冲").first()
print(author_obj.au_detail.tel)
# 反向查询(按表名:author):
# 查询所有住址在黑木崖的作者的姓名
au_detail_obj = models.AuthorDetail.objects.filter(addr="黑木崖")
for au in au_detail_obj:
print(au.author.name)
(3)多对多查询 (Author 与 Book)
# 独孤九剑所有作者的名字以及手机号
book_obj = models.Book.objects.filter(title="独孤九剑").first()
for au in book_obj.authors.all():
print(au.name, au.au_detail.tel)
# 反向查询(按表名:book_set):
# 查询令狐冲出过的所有书籍的名字
au_obj = models.Author.objects.filter(name="令狐冲").first()
for book in au_obj.book_set.all():
print(book.title)
注意:
你可以通过在 ForeignKey() 和ManyToManyField的定义中设置 related_name 的值来覆写 FOO_set 的名称。例如,如果 Book model 中做一下更改:
publish = models.ForeignKey("Publish", on_delete=models.CASCADE, related_name="book_list")
那么接下来就会如我们看到这般:
# 查询 明教出版社出版过的所有书籍
publish=Publish.objects.get(name="明教出版社")
book_list=publish.book_list.all() # 与明教出版社关联的所有书籍对象集合
5.基于双下划线的跨表查询
Django 还提供了一种直观而高效的方式在查询(lookups)中表示关联关系,它能自动确认 SQL JOIN 联系。要做跨关系查询,就使用两个下划线来链接模型(model)间关联字段的名称,直到最终链接到你想要的model 为止。
正向查询按字段,反向查询按表名小写用来告诉ORM引擎join哪张表
"""
正向: 字段名称__跨表的字段名称
----------------------------->
Book Publish
<-----------------------------
反向: 小写表名__跨表的字段名称
"""
(1)一对多查询
# 练习: 查询华山出版社出版过的所有书籍的名字与价格(一对多)
# 正向查询 按字段:publish
book_title_price1 = models.Book.objects.filter(publish__name="华山出版社").values_list("title", "price")
print(book_title_price1)
# 反向查询 按表名:book
book_title_price2 = models.Publish.objects.filter(name="华山出版社").values_list("book__title", "book__price")
print(book_title_price2)
(2)多对多查询
# 练习: 查询令狐冲出过的所有书籍的名字(多对多)
# 正向查询 按字段:authors:
book_name = models.Book.objects.filter(authors__name="令狐冲").values("title")
print(book_name)
# 反向查询 按表名:book
book_name = models.Author.objects.filter(name="令狐冲").values("book__title")
print(book_name)
(3)一对一查询
# 查询令狐冲的手机号
au_tel =models.Author.objects.filter(name ="令狐冲").values("au_detail__tel")
print(au_tel)
# 反向查询
au_tel = models.AuthorDetail.objects.filter(author__name="令狐冲").values("tel")
print(au_tel)
(4)进阶练习(连续跨表)
# # 正向查询
bname_aname = models.Book.objects.filter(publish__name="华山出版社").values("title","authors__name")
print(bname_aname)
# 反向查询
bname_aname = models.Publish.objects.filter(name="华山出版社").values("book__title","book__authors__name")
print(bname_aname)
# 练习2: 手机号以132开头的作者出版过的所有书籍名称以及出版社名称
# 正向查询
bname_pname = models.Book.objects.filter(authors__au_detail__tel__startswith="134").values("title", "publish__name")
print(bname_pname)
# 反向查询1
bname_pname = models.Author.objects.filter(au_detail__tel__startswith="134").values("book__title", "book__publish__name")
print(bname_pname)
# 反向查询2
bname_pname = models.AuthorDetail.objects.filter(tel__startswith="134").values("author__book__title", "author__book__publish__name")
print(bname_pname)
Django 学习 之ORM多表操作的更多相关文章
- Django框架06 /orm多表操作
Django框架06 /orm多表操作 目录 Django框架06 /orm多表操作 1. admin相关操作 2. 创建模型 3. 增加 4. 删除 5. 修改 6. 基于对象的跨表查询 7. 基于 ...
- Django框架05 /orm单表操作
Django框架05 /orm单表操作 目录 Django框架05 /orm单表操作 1. orm使用流程 2. orm字段 3. orm参数 4. orm单表简单增/删/改 5. orm单表查询 5 ...
- day 46 Django 学习3 数据库单表操作以及反向解析
前情提要: Django 已经学了不少了, 今天学习链接数据库的操作.以及相关的反向解析等 一:反向解析 1:反向解析模板层 跳转时设定url会随着前面的路由改变而改变 2:反向解析之 ...
- Django之模型---ORM 多表操作
多表操作 创建表模型 from django.db import models # Create your models here. class Author(models.Model): nid = ...
- django框架基础-ORM单表操作-长期维护
############### 单表操作-添加数据 ################ import os if __name__ == '__main__': os.environ.set ...
- Django视图之ORM连表操作一
1 项目路径结构树 2 models创建类 from django.db import models class UserType(models.Model): ''' 用户类型 ''' title ...
- Django之模型---ORM 单表操作
以上一随笔中创建的book表为例讲解单表操作 添加表记录 方式一 # create方法的返回值book_obj就是插入book表中的python葵花宝典这本书籍纪录对象 book_obj=Book.o ...
- python django基础五 ORM多表操作
首先在创建表的时候看下分析一下 1.作者表和作者详细地址表 一对一关系 理论上谁都能当主表 把Author设置成主表 au=models.OneToOneField(to='AuthorDetail ...
- django框架基础-ORM跨表操作-长期维护
############### 一对一跨表查询 ################ import os if __name__ == '__main__': os.environ.setde ...
随机推荐
- vscode设置python代码补全时函数自动加上小括号
vscode设置python代码补全时函数自动加上小括号 vscode的python代码补全插件默认安装时是不会自动补全括号的,感觉不是和方便 以下介绍下自动补上小括号的方法 可能部分同学设置了还是没 ...
- typo3 网站迁移
最近再弄这个typo3,虽然说看不怎么动,但是迁移嘛,最笨的办法就是整体过去,就是数据量太大了,哈哈,我先写一下我的笨办法: 注意:每个版本的typo3对php,mysql,apache的版本都有要求 ...
- 【转】弹出USB大容量存储设备时出问题的解决方法
原文链接 如下图所示,这个问题,相信很多人都有遇到过,而且经常难以解决,试了很多方法都无效.到最后,只能抱着侥幸的心理直接拔出,如果运气好,可能没有事,如果运气不好,你的U盘或者移动硬盘就要从此报废了 ...
- 洛谷P1060开心的金明(滚动数组优化)
题目描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间他自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过NNN元钱就行”. ...
- __str__()方法和__repr__()方法
有时候我们想让屏幕打印的结果不是对象的内存地址,而是它的值或者其他可以自定义的东西,以便更直观地显示对象内容,可以通过在该对象的类中创建或修改__str__()或__repr__()方法来实现(显示对 ...
- 【PAT甲级】1048 Find Coins (25 分)(二分)
题意: 输入两个正整数N和M(N<=10000,M<=1000),然后输入N个正整数(<=500),输出两个数字和恰好等于M的两个数(小的数字尽可能小且输出在前),如果没有输出&qu ...
- Spring MVC 解读——@Autowired、@Controller、@Service从原理层面来分析
目录(?)[+] Spring MVC 解读Autowired 一Autowired 二BeanPostProcessor 三磨刀砍柴 四Bean 工厂 五实例化与装配 六执行装配 七一切的开始 ...
- location练习!(重点)
写location最重要的就是hosts文件,添加一次域名跳转就得添加一条hosts文件 hosts文件: 192.168.200.120 www.a.com 192.168.200.119 www. ...
- Weka算法算法翻译(部分)
目录 Weka算法翻译(部分) 1. 属性选择算法(select attributes) 1.1 属性评估方法 1.2 搜索方法 2. 分类算法 2.1 贝叶斯算法 2.2 Functions 2.3 ...
- ECS 系统 Entity-Component-System
已经推出了很久了, 貌似也有一些人开始使用, 我是在看守望先锋的程序设计相关文章的时候看到 ECS 的, 从它的设计逻辑上看, 核心就是 Composition over inheritance (o ...