Django的模型层(2)- 多表操作(上)
一、创建模型
例:我们来假定下面这些概念,字段和关系
作者模型:一个作者有姓名和年龄。
作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息。作者详情模型和作者模型之间是一对一(one-to-one)的关系。
出版社模型:出版社有名称,所在城市以及email。
书籍模型: 书籍有书名和出版日期,一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多(many-to-many)的关联关系; 一本书只应该由一个出版社出版,所以出版社和书籍是一对多(one-to-many)的关系。
模型建立如下代码:
from django.db import models # Create your models here.
class Author(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
age = models.IntegerField()
# 与AuthorDetail建立一对一的关系,author表自动加authorDetail_id字段
authorDetail = models.OneToOneField(to="AuthorDetail", on_delete=models.CASCADE) class AuthorDetail(models.Model):
nid = models.AutoField(primary_key=True)
birthday = models.DateField()
telephone = models.BigIntegerField()
addr = models.CharField(max_length=64) 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=5, decimal_places=2)
# 与Publish建立一对多的关系,外键字段必须建立在多的一方,生成publish_id
publish = models.ForeignKey(to="Publish", to_field="nid", on_delete=models.CASCADE)
# 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表book_authors,且第三张表有book_id和author_id字段
authors = models.ManyToManyField(to='Author',)
生成表如下图:
注意事项:
1)表的名称myapp_modelName,是根据模型中的元数据自动生成的,也可以覆写为别的名称;
2)id 字段是自动添加的;
3)对于外键字段,Django 会在字段名上添加"_id" 来创建数据库中的列名;
4)这个例子中的CREATE TABLE SQL 语句使用PostgreSQL 语法格式,要注意的是Django 会根据settings 中指定的数据库类型来使用相应的SQL 语句;
5)定义好模型之后,你需要告诉Django使用这些模型。你要做的就是修改配置文件中的INSTALL_APPSZ中设置,在其中添加models.py所在应用的名称;
6)外键字段 ForeignKey 有一个参数null=True的设置(它允许外键接受空值 NULL),你可以赋给它空值 None;
二、添加表记录
操作前先简单的录入一些数据:
publish表:
authordetail表:
author表:
1、一对一
示例一(添加一条作者信息):
# 先添加作者详细信息
authorDetail_obj = AuthorDetail.objects.create(tel=tel, addr=addr)
# 再添加作者,因为他依赖AuthorDetail表
Author.objects.create(
name=name,
age=age,
email=email,
authorDetail=authorDetail_obj)
2、一对多(给关联字段所在的表,即book表添加记录)
方式一:
publish_obj = Publish.objects.get(nid=1)
book_obj = Book.objects.create(
title="金瓶眉",
publishDate="2012-12-12",
price=100,
publish=publish_obj) # 对象赋值对象
方式二:
book_obj = Book.objects.create(
title="金瓶眉",
publishDate="2012-12-12",
price=100,
publish_id=1) # 字段值赋值给字段名
核心:book_obj.publish与book_obj.publish_id是什么?
3、多对多(核心是给第三张关系表添加记录)
方式一:
# book_obj为当前生成的书籍对象
book_obj = Book.objects.create(
title="追风筝的人",
price=200,
publishDate="2012-11-12",
publish_id=1)
# 查询出为书籍绑定的作者对象
yuan = Author.objects.filter(name="yuan").first() # 若yuan在Author表主键是2
egon = Author.objects.filter(name="alex").first() # 若egon在Author表主键是1
# 因Book表与Author表绑定多对多关系,即向关系表book_authors中添加纪录
book_obj.authors.add(yuan, egon) # 将某些特定的 model 对象添加到被关联对象集合
方式二:
book_obj.authors.add(1, 2) # 直接给新创建的书籍对象绑定两个作者id,即关联表中添加2条记录
方式三:
book_obj.authors.add(*[]) # 本质同方式二,位置参数方式传参
核心:book_obj.authors.all()是什么?
4、补充:多对多关系的其他常用API
book_obj.authors.remove() # 将某个特定的对象从被关联对象集合中去除
# book_obj.authors.remove(*[])
book_obj.authors.clear() # 清空被关联对象集合
book_obj.authors.set() # 先清空再设置
例如:
egon_obj = Author.objects.filter(name="egon").first()
book = Book.objects.filter(nid=3).first()
# 解除nid为3的书籍与作者egon的关系,
book.authors.remove(egon_obj) # 即删除第三张表中书籍是3,作者是egon的记录
# 假设已知egon的id为1 ,则可以直接根据id解除关系
book.authors.remove(1) # 即删除第三张表中book_id是3,author_id是1的记录 # 删除nid=3的书籍的所有作者记录
book.authors.clear() # 删除book_id为3的所有记录,不管author_id为多少 # 只为nid=3的作者绑定一个id为1的作者
book.authors.set(1) # 相当于先解除,即clear(),再绑定,即add(1)
三、查询表记录
查询分为:
跨表查询(基于对象跨表查询、基于双下划线跨表查询);
聚合查询;
分组查询;
F与Q查询;
正式学习查询之前,我们先来了解一下,什么是正向查询?什么是反向查询?由关联字段所在的表去查询非关联字段所在的表,就是正向查询,反之为反向查询。例如:
① 一对多关系,“多”的一方创建关联字段并通过ForeignKey方法建立关联关系,即关联字段所在的表(ForeignKey方法所在的表)去查询另一个表时为正向查询;反之为反向查询。
② 多对多关系,任一方创建关联字段并通过ManyToMany方法建立关联关系,即关联字段所在的表(ManyToMany方法所在的表)去查询另一个表时为正向查询;反之为反向查询。
③ 一对一关系,任一方通过创建关联字段并通过OneToOne方法建立关联关系,即关联字段所在的表(OneToOne方法所在的表)去查询另一个表时为正向查询;反之为反向查询。
1、基于对象跨表查询(会被翻译成sql子查询)
1)一对多查询(Publish表与Book表,且Book表为关联字段所在的表)
a、正向查询(按字段:publish)(多查一)
# 查询主键为1的书籍的出版社所在城市
book_obj = Book.objects.filter(pk=1).first()
publish_obj = book_obj.publish # 主键为1的书籍对象关联的出版社对象
print(publish_obj.city)
b、反向查询(按表名_set:book_set)(一查多)
# 查询苹果出版社出版的所有书籍名称
publish = Publish.objects.get(name="苹果出版社")
book_list = publish.book_set.all() # 与苹果出版社关联的所有书籍对象集合(QuerySet类型)
for book_obj in book_list:
print(book_obj.title)
2)多对多查询(Author与Book)
a、正向查询(按字段:authors)
# 查询金瓶眉这本书所有作者的名字以及手机号
book_obj = Book.objects.filter(title="金瓶眉").first()
authors_list = book_obj.authors.all()
for author_obj in authors_list:
print(author_obj.name, author_obj.authorDetail.telephone)
b、反向查询(按表名_set:book_set)
# 查询egon写的所有书籍的名字
author_obj = Author.objects.get(name="egon")
book_list = author_obj.book_set.all() # 与egon作者相关的所有书籍
for book_obj in book_list:
print(book_obj.title)
3)一对一查询(Author与AuthorDetail)
a、正向查询(按字段:authorDetail)
# 查询作者egon的手机号码
egon = Author.objects.filter(name="egon").first()
print(egon.authorDetail.telephone)
b、反向查询(按表名:author)
# 查询所有住址在北京的作者的姓名
authorDetail_list = AuthorDetail.objects.filter(addr="beijing")
for obj in authorDetail_list:
print(obj.author.name)
注意:你可以通过在ForeignKey()和ManyToManyField()的定义中设置 related_name 的值来覆写“表名_set”的名称。例如,如果 Book表中做以下更改:
publish = models.ForeignKey(Publish, related_name='bookList', on_delete=models.CASCADE)
那么接下来就会如我们看到这般:
# 查询人民出版社出版过的所有书籍
publish_obj=Publish.objects.get(name="人民出版社")
book_list=publish_obj.bookList.all() # 与人民出版社关联的所有书籍对象集合
四、补充
1、Foreignkey()用法及参数解释
ForeignKey(to="Publish", to_field="nid", on_delete=models.CASCADE)方法参数解释
to="Publish":表示跟Publish表建立一对多关系,也可以直接写成"Publish"(需要带引号,不带引号则models.py中建立表时有顺序要求,即关联表Publish在前边);
to_field="nid":跟关联表(这里是Publish表)的哪个字段建立联系,此参数不写则默认跟主键字段建立联系;
on_delete=models.CASCADE:级联删除(即同步删除,同步更新),Django1.11版本默认就是级联删除,可不写,但2版本要求必须写,否则报错;
注意:级联删除表示删除主表记录,从表(ForeignKey所在表)对应记录也会自动删除;而删除从表记录,主表记录不会自动删除。
Django的模型层(2)- 多表操作(上)的更多相关文章
- Django之模型层(单表操作)
一.ORM简介 MVC和MTV框架中包含一个重要部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库. ORM是‘对象-关系- ...
- Django的模型层(2)---多表操作
多表操作 创建模型 实例:我们来假定下面这些概念,字段和关系 作者模型:一个作者有姓名和年龄. 作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息.作者详情模型和作者模型之间是一对 ...
- Django之模型层(多表操作)
一.创建模型 1,一对多关系 一本书只有一个出版社,一个出版社可以出版多本书,从而书与出版社之间就构成一对多关系,书是‘多’的一方,出版社是‘一’的一方,我们在建立模型的时候,把外键写在‘多’的一方, ...
- {django模型层(二)多表操作}一 创建模型 二 添加表记录 三 基于对象的跨表查询 四 基于双下划线的跨表查询 五 聚合查询、分组查询、F查询和Q查询
Django基础五之django模型层(二)多表操作 本节目录 一 创建模型 二 添加表记录 三 基于对象的跨表查询 四 基于双下划线的跨表查询 五 聚合查询.分组查询.F查询和Q查询 六 xxx 七 ...
- Django模型层之单表操作
Django模型层之单表操作 一 .ORM简介 我们在使用Django框架开发web应用的过程中,不可避免地会涉及到数据的管理操作(如增.删.改.查),而一旦谈到数据的管理操作,就需要用到数据库管理软 ...
- day 70 Django基础五之django模型层(二)多表操作
Django基础五之django模型层(二)多表操作 本节目录 一 创建模型 二 添加表记录 三 基于对象的跨表查询 四 基于双下划线的跨表查询 五 聚合查询.分组查询.F查询和Q查询 六 ORM ...
- day 69 Django基础五之django模型层(一)单表操作
Django基础五之django模型层(一)单表操作 本节目录 一 ORM简介 二 单表操作 三 章节作业 四 xxx 一 ORM简介 MVC或者MVC框架中包括一个重要的部分,就是ORM,它实现 ...
- day 56 Django基础五之django模型层(二)多表操作
Django基础五之django模型层(二)多表操作 本节目录 一 创建模型 二 添加表记录 三 基于对象的跨表查询 四 基于双下划线的跨表查询 五 聚合查询.分组查询.F查询和Q查询 六 ORM ...
- day 55 Django基础五之django模型层(一)单表操作
Django基础五之django模型层(一)单表操作 本节目录 一 ORM简介 二 单表操作 三 章节作业 四 xxx 一 ORM简介 MVC或者MVC框架中包括一个重要的部分,就是ORM,它 ...
- Django基础五之django模型层(一)单表操作
一 ORM简介 MVC或者MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极大的减轻了开发人 ...
随机推荐
- 重启tomcat但是session仍然有效的解决方法
参考:http://www.blogjava.net/freeman1984/archive/2010/03/30/316901.html server.xml,在你的webapp的Context节点 ...
- sitemesh 学习之 meta 引入
在上篇笔记学习了sitemesh的基本用法,这里还有另一种用法 在sitemesh.jar有一个默认的sitemesh-default文件 ,这个文件是可以指定的 可以指定的文件名的sitemesh. ...
- mysql乐观锁和悲观锁
在多用户环境中,在同一时间可能会有多个用户更新相同的记录,这会产生冲突.这就是著名的并发性问题. 悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作. 乐观锁:假设不会发生并发冲突,只在提交 ...
- DHCP中继器
DHCP客户机和服务器在不同的子网内,客户机向服务器申请IP地址,这就要用到DHCP中继代理.DHCP中继代理实际上是一种软件技术,安装了DHCP中继代理的计算机称为DHCP中继代理服务器,它承担不同 ...
- python 差分包制作-如何来制作差分包?
继百度网盘爬虫,百度图片爬虫后这是本人第三篇有关python的文章了,由于本人之前做过嵌入式的一些东西,其中会涉及到差分包的制作,所以这篇文章想谈谈如何利用python来制作差分包,如果你对嵌入式的东 ...
- impala+kudu
[impala建表]kudu的表必须有主键,作为分区的字段需排在其他字段前面. [range分区](不推荐)CREATE TABLE KUDU_WATER_HISTORY ( id STRING, y ...
- impala+hdfs+parquet格式文件
[创建目录]hdfs dfs -mkdir -p /user/hdfs/sample_data/parquet [赋予权限]sudo -u hdfs hadoop fs -chown -R impal ...
- mean 快速开发和现有技术的对比分析
最近无聊的时候,网上看了下全栈开发的相关资料,发现了mean这个好玩的东西.可能我是一个比较传统的开发,接触.net 已经将近快8年了,一直在传统的后端多层架构的模式下开发,一时对这个新的东西就喜欢研 ...
- 第一百三十八节,JavaScript,封装库--插件
JavaScript,封装库--插件 库主要是用来封装一般JavaScript的常规操作代码,而拖拽这种特效代码属于功能性代码,并不是必须的,所以这种类型的代码,我们建议另外封装,在需要的时候作为插件 ...
- 简单说明什么是递归?什么情况会使用?并使用java实现一个简单的递归程序。
解答: 1)递归做为一种算法在程序设计语言中广泛应用.是指函数/过程/子程序在运行过程中直接或间接调用自身而产生的重入现象. 2)递归算法一般用于解决三类问题: a.数据的定义是按递归定义的.(Fib ...