from django.db import models
class Author(models.Model):
"""
作者表
"""
name=models.CharField( max_length=32)
age=models.IntegerField()
# authorDetail=models.OneToOneField(to="AuthorDetail",to_field="nid",on_delete=models.CASCADE) #
au=models.OneToOneField("AuthorDetail",on_delete=models.CASCADE)
# 与AuthorDetail表创建一对一对应关系,不写to_field默认会跟AuthorDetail表中的id字段关联
class AuthorDetail(models.Model):
"""
作者详细信息表
"""
birthday=models.DateField()
telephone=models.CharField(max_length=11)
addr=models.CharField(max_length=64)
# class Meta:
# db_table='authordetail' #指定表名
# ordering = ['-id',]
class Publish(models.Model):
"""
出版社表
"""
name=models.CharField( max_length=32)
city=models.CharField( max_length=32)
class Book(models.Model):
"""
书籍表
"""
title = models.CharField( max_length=32)
publishDate=models.DateField()
price=models.DecimalField(max_digits=5,decimal_places=2)
publishs=models.ForeignKey(to="Publish",on_delete=models.CASCADE,)
# ForeignKed是建立外键关联,on_delete是级联删除,如果没有写关联表的关联字段就会默认与被关联表的id字段关联
authors=models.ManyToManyField('Author',)
# 执行这个ManyToMany语句会自动创建Book表和Author表关联关系的第三张表
增
一对一的增加:两张表是一一对应的关系,(OneToOneField)
# 第一种方式,使用对象的方式来增加关联字段
# 先获取被关联字段中的对象,
obj_aut = models.AuthorDetail.objects.get(nid=4)
models.Author.objects.create(
name = '小猿',
age = '18',
authorDetail=obj_aut # 必须写的是Author这个类的authorDetail属性,将关联的字段id以对象的形式传入,它会自动的获取id,并与AuthorDetail表进行关联,
)
# 第二种方式,使用字段名
models.Author.objects.create(
name = '小猿',
age = '18',
authorDetail_id=5 # 使用字段名直接将被关联表的id字段进行关联
)
一对多的增加:(ForeignKey)
# 跟一对一一样也是有两种创建的方法,
pub_obj = models.Publish.objects.get(nid=1)
models.book.objects.create(
title='白鹿原',
publishDate='2019-2-3',
price=213.00,
publish=pub_obj
)
多对多的增加:(ManyToManyField)
# 首先找出几个被关联表的对象
author1 = models.Author.objects.get(nid=2)
author2 = models.Author.objects.get(nid=3)
book_obj = models.book.objects.create(
title='python',
publishDate='2018-5-4',
price=562.00,
publish_id=3,
)
# 首先找到这个类创建多对多关联的属性名,直接使用这个属性名就可以对这两张表的关联表进行添加字段值,使用add方式直接添加
# 这里有三种添加方式,都可以对关联表进行添加操作
1.这是获取对象进行添加
book_obj.authors.add(author1,author2)
2.使用列表的打散方式,进行添加
book_obj.authors.add(*[2,3]) # 用的多一点
3.直接使用别关联表的id字段就可以进行添加关联
book_obj.authors.add(2,3)
删除
1.一对一表的删除,删除时
# 如果删除的是被关联的表数据,那么关联的表的对应数据也会被删除
models.AuthorDetail.objects.get(nid=2).delete()
# 如果删除的是关联表的数据,被关联的表不会改变
models.Author.objects.get(nid=3).delete()
2.一对多表的删除:
# 如果删除的是被关联的表数据,那么关联的表的对应数据也会被删除
models.Publish.objects.get(nid=2).delete()
# 如果删除的是关联表的数据,被关联的表不会改变
models.book.objects.get(nid=6).delete()
3.多对多表的删除:
# 首先通过类获取对应的数据对象
book_obj = models.book.objects.get(nid=5)
# remove中的数值是表示删除与这个表关联的值为1的这条数据
book_obj.authors.remove(1) # 通过对象调用这个类中的authors属性,通过这个属性名来操作第三张表进行相关的操作
book_obj.authors.clear() # 清除
book_obj.authors.set(['1','5']) # 先清除再添加,相当于修改
改
#两种方式
1.
# 通过类获取对应的数据对象
pub_obj = models.Publish.objects.get(nid=1)
models.book.objects.filter(nid=3).update(
title = 'go语言',
publish = pub_obj, # 拿到类属性,传入获取的对象进行修改值,自动转换
)
2.
models.book.objects.filter(nid=3).update(
title = 'go语言',
publish_id = 1, #直接通过表字段更换关联字段的id
)
# 关系属性写在表1,关联到表2,那么通过表1的数据去找表2的数据,叫做正向查询,返过来就是反向查询
1. 一对一表查询:
正向查询
通过作者名去被关联的表中查找电话号
# 首先通过类来获取数据对象
aut_obj = models.Author.objects.filter(name='小猿').first()
# 通过这个对象直接调用类中关联字段的属性名authorDetail
aut_obj.authorDetail.telephone
反向查询
通过被关联的表中的数据找关联表中的数据
# 首先通过类来获取数据对象
phone = models.AuthorDetail.objects.filter(telephone='123').first()
# 通过这个对象直接后边接上关联的表的类名(小写),在接上自己要查找的属性
name = phone.author.name
2. 一对多查询:
正向查询:
查询go语言是哪个出版社出版的?
book_obj = models.book.objects.get(title='go语言')
name = book_obj.publish.name
反向查询:
查询那个出版社出版了那些书?
pub_obj = models.Publish.objects.get(nid=1)
book_name = pub_obj.book_set.all() # 获取到多条数据 类名小写加_set
for i in book_name:
print(i.title)
3. 多对多
正向查询
obj = models.Book.objects.filter(title='海狗的怂逼人生').first()
ret = obj.authors.all()
print(ret) #<QuerySet [<Author: 王洋>, <Author: 海狗>]>
for i in ret:
print(i.name)
查询一下海狗写了哪些书 -- 反向查询
obj = models.Author.objects.filter(name='海狗').first()
ret = obj.book_set.all()
print(ret)
for i in ret:
print(i.publishs.name)
print(i.title)
django为表与表之间存在关联关系提供了一种高效的查询方法 ----- 双下划线的跨表查询(就使用两个下划线来链接模型(model)间关联字段的名称,直到最终链接到你想要的model 为止。)
#基于双下划线的查询就一句话:正向查询按字段,反向查询按表名小写用来告诉ORM引擎join哪张表,一对一、一对多、多对多都是一个写法,注意,我们写orm查询的时候,哪个表在前哪个表在后都没问题,因为走的是join连表操作。
语法操作
1.一对一
# 查询大猿的电话号码,
正向:
ret = models.Author.objects.filter(name='大猿').values('au__telephone')
# <QuerySet [{'au__telephone': '456'}]> 获取到的是一个queryset对象,
首先根据已知条件查询到对应的数据,在加上values,在values中写入关联字段的名称+上下划线+要查询的字段名称
反向:
ret = models.AuthorDetail.objects.filter(author__name='大猿').values('telephone')
# <QuerySet [{'telephone': '456'}]> 同样获取到的是一个queryset对象
反向查询就是通过需要获取信息的这张表来获取数据,查询的条件写已知的作者姓名,后边的values中是需要获取数据的字段名
2.一对多:
# 查询北京出版社出版那些书?
正向:
ret = models.Publish.objects.filter(name='北京出版社').values('book__title')
# <QuerySet [{'book__title': '三国'}, {'book__title': '西游记'}]>
这个需要注意的是在values中的值是表名加字段名"book__title",Book表的名字需要小写
反向:
ret = models.Book.objects.filter(publishs__name='北京出版社').values('title')
# <QuerySet [{'title': '三国'}, {'title': '西游记'}]>
注意在filter中需要写的是关联字段名加双下划线在加字段名
3.多对多:
#查询三国是哪些作者写的?
正向:
ret = models.Book.objects.filter(title='三国').values('authors__name')
# <QuerySet [{'authors__name': '大猿'}, {'authors__name': '小猿'}]>
反向:
ret = models.Author.objects.filter(book__title='三国').values('name')
# <QuerySet [{'name': '大猿'}, {'name': '小猿'}]>
4. related_name
# 查询一下24期出版社出版了哪些书
ret = models.Publish.objects.filter(name='24期出版社').values('xxx__title') #xxx代替反向查询的小写表名
print(ret)
aggregate
(*args, **kwargs)
操作:
1.查询书籍的平均价格和最大价格
# 首先需要导入相应的包
from django.db.models import Avg,Max
ret = models.Book.objects.all().aggregate(a=Avg('price'),m=Max('price'))
# ret = models.Book.objects.aggregate(a=Avg('price'),m=Max('price')) 这个也可以查询所有的值
# {'a': 456.4, 'm': Decimal('856.00')} 查出的数据是一个字典不是一个queryset类型的数据,这说明这个不能在对其进行加工,也就是说聚合查询是orm的结束语句
aggregate()
是QuerySet
的一个终止子句,意思是说,它返回一个包含一些键值对的字典。键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。如果你想要为聚合值指定一个名称,可以向聚合子句提供它。
annotate()为调用的QuerySet
中每一个对象都生成一个独立的统计值(统计方法用聚合函数)。
操作
# 获取每个出版社出版的书的平均价格
1.
from django.db.models import Avg,Max
ret = models.Book.objects.values('publishs_id').annotate(a=Avg('price'))
# ret = models.Book.objects.values('publishs').annotate(a=Avg('price')) 同样可以
annotate前边的values是分组的依据,annotate是分组的统计数据
ret = models.Book.objects.values('publishs').annotate(a=Avg('price')) #注意:annotate里面必须写个聚合函数,不然没有意义,并且必须有个别名=,别名随便写,但是必须有,用哪个字段分组,values里面就写哪个字段,annotate其实就是对分组结果的统计,统计你需要什么。
2.如果不写分组的依据就会默认以这个表的id字段进行分组,求值时利用了双下划线的查询方式
from django.db.models import Avg,Max
ret = models.Publish.objects.annotate(a=Avg("book__price")).values('name','a')
# <QuerySet [{'name': '北京出版社', 'a': 324.5}, {'name': '上海出版社', 'a': 490.5}, {'name': '深圳出版社', 'a': 652.0}]>
在我们需要对一个表中的几个字段的数据进行比较时,是不是比较麻烦,那么Django 提供 F() 来做这样的比较,F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。
操作:
1. 将评论数大于点赞数的数据取出
ret = models.Book.objects.filter(comment__gt=F('good'))
# <QuerySet [<Book: 红楼梦>]>
可以看出这样比较会省事,F中所写的字段名就是直接拿出来进行比较
2. 将每个数据的价格增加100
models.Book.objects.all().update(
price=F('price')+100 # F获取到price字段对这个字段继续增加
)
filter()
等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR
语句),你可以使用Q 对象
Q
对象可以使用&(与)
、|(或)、~(非)
操作符组合起来。当一个操作符在两个Q
对象上使用时,它产生一个新的Q
对象。
操作:
1. 查询书籍价格在大于500或者评论数在小于100的书籍
ret = models.Book.objects.filter(Q(price__gt=500)|Q(comment__lt=100))
# <QuerySet [<Book: 西游记>, <Book: 水浒传>, <Book: 红楼梦>, <Book: 平凡的世界>]>
原文:https://www.cnblogs.com/zhufanyu/p/11666549.html