1.建表
from django.db import models
# Create your models here.
class AuthorDtail(models.Model):
nid = models.AutoField(primary_key=True)
birthday = models.DateField()
telephone = models.BigIntegerField()
addr = models.CharField(max_length=64)
class Author(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
age = models.IntegerField()
# OneToOneField可以建立在两个模型中的任意一个
authorDetail = models.OneToOneField(to="AuthorDtail", to_field="nid", on_delete=models.CASCADE)
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=9,decimal_places=2)
# 与Publish建立一对多的关系,外键字段建立在多的一方
publish = models.ForeignKey(to="Publish", to_field="nid", on_delete=models.CASCADE)
# 多对多,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表
authors = models.ManyToManyField(to="Author")
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对象
# , ]>
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) # , , , ]>
# SQL语句:
return render(request, "index.html")
2.2.2.3基于对象查询--多对多查询
from django.shortcuts import render
from app1.models import *
def index(request):
# 多对多正向查询:查询Sanguo这本书的所有作者名字
# 书和作者是多对多关系,返回值是queryset集合。
# , ]>
author_list = Book.objects.filter(title="SanGuo").first().authors.all()
print(author_list)
# 多对多反向查询:查询vita出版过的所有书籍名称
# 书和作者是多对多关系,返回值是queryset集合。
# , , , , ]>
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) #
# 方式二反向查询:
ret2 = Publish.objects.filter(book__title="SanGuo").values("name")
print(ret2) #
# 一对多查询:查询 AA_publish出版社出版的书籍名称
# 返回值是queryset对象
# 方式一正向查询:
ret3 = Publish.objects.filter(name="AA_publish").values("book__title")
print(ret3) #
# 方式二反向查询:
ret4 = Book.objects.filter(publish__name="AA_publish").values("title")
print(ret4) #
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) #
# 方式二:反向查询
ret2 = Author.objects.filter(book__title="SanGuo").values("name")
print(ret2) #
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) #
# 方式二:反向查询
ret2 = AuthorDetail.objects.filter(author__name="vita").values("telephone")
print(ret2) #
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) #
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) #
# 正向查询
ret2 = Book.objects.values("publish__name").annotate(book_count=Count("nid"))
print(ret2) #
# 正向查询,最后values取值
ret3 = Book.objects.values("publish__nid").annotate(book_count=Count("nid")).values("publish__name","book_count")
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):
# 总结 跨表的分组查询的模型:
# 每一个后表模型.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")