1. 表关系models
from django.db import models class Author(models.Model): """ 作者表 """ name = models.CharField(max_length=32) age = models.IntegerField() sex = models.CharField(max_length=20, default='male') au = models.OneToOneField("AuthorDetail",on_delete=models.CASCADE) def __str__(self): return self.name 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',] def __str__(self): return self.telephone + self.addr class Publish(models.Model): """ 出版社表 """ name = models.CharField(max_length=32) city = models.CharField(max_length=32) def __str__(self): return self.name class Book(models.Model): """ 书籍表 """ title = models.CharField(max_length=32) publishDate = models.DateField() price = models.DecimalField(max_digits=5,decimal_places=2) comment = models.FloatField(default=100) # 评论数 good = models.FloatField(default=100) # 点赞数 # publishs=models.ForeignKey(to="Publish",on_delete=models.CASCADE 级联,related_name='xxx',related_query_name='xx' 设置别名,两者都存在,按后者) publishes = models.ForeignKey(to="Publish",on_delete=models.CASCADE,) authors = models.ManyToManyField(to='Author',) def __str__(self): return self.title
2. 增加
1. 一对一
# au_obj = models.AuthorDetail.objects.get(id=4) models.Author.objects.create( name='海贼王', age=59, # 两种方式 au_id=4 # 以id形式添加 # au=au_obj # 以对象形式添加 )
2. 一对多
# pub_obj = models.Publish.objects.get(id=3) models.Book.objects.create( title='xx2', price=13, publishDate='2011-11-12', # publishs=pub_obj , #类属性作为关键字时,值为model对象 publishs_id=3 # 如果关键字为数据库字段名称,那么值为关联数据的值 )
3. 多对多
# ziwen = models.Author.objects.get(id=3) # haigou = models.Author.objects.get(id=5) new_obj = models.Book.objects.create( title='护理第二部', price=0.5, publishDate='2019-09-29', publishs_id=2, ) new_obj.authors.add(3,5) # #*args **kwargs new_obj.authors.add(*[3,5]) # 用的最多, new_obj.authors.add(ziwen, haigou) new_obj.authors.set([1,3]) 正向:对象.关联属性.set(列表) 反向:对象.表名小写_set.set(列表)
3. 删除
# 一对一 # models.AuthorDetail.objects.filter(id=3).delete() # models.Author.objects.filter(id=3).delete() # 一对多 # models.Publish.objects.filter(id=3).delete() # models.Book.objects.filter(id=4).delete() # 多对多 book_obj = models.Book.objects.get(id=2) # book_obj.authors.add() # 添加 # book_obj.authors.remove(1) #删除 2 1 # book_obj.authors.clear() # 清除 # book_obj.authors.set(['1','5']) # 先清除再添加,相当于修改
注意:
对于ForeignKey对象,clear()和remove()方法仅在null=True时存在(一对多,多对一)
ForeignKey字段没设置null=True时,
class Book(models.Model): title = models.CharField(max_length=32) publisher = models.ForeignKey(to=Publisher)
没有clear()和remove()方法:
>>> models.Publisher.objects.first().book_set.clear() Traceback (most recent call last): File "<input>", line 1, in <module> AttributeError: 'RelatedManager' object has no attribute 'clear'
当ForeignKey字段设置null=True时,
class Book(models.Model): name = models.CharField(max_length=32) publisher = models.ForeignKey(to=Class, null=True)
此时就有clear()和remove()方法:
>>> models.Publisher.objects.first().book_set.clear()
4. 改
ret = models.Publish.objects.get(id=2) models.Book.objects.filter(id=5).update( # title='华丽丽', publishs=ret, # publishs_id=2, )
5. 外键
# 查询 # 一对一 # 关系属性写在表1,关联到表2,那么通过表1的数据去找表2的数据,叫做正向查询,返过来就是反向查询 # 查询一下王洋的电话号码 # 正向查询 对象.属性 # obj = models.Author.objects.filter(name='王洋').first() # ph = obj.au.telephone # print(ph) # 查一下电话号码为120的作者姓名 # 反向查询 对象.小写的表名 # obj = models.AuthorDetail.objects.filter(telephone=120).first() # ret = obj.author.name #陈硕 # print(ret) # 一对多 # 查询一下 海狗的怂逼人生这本书是哪个出版社出版的 正向查询 # obj = models.Book.objects.filter(title='海狗的怂逼人生').first() # ret = obj.publishs.name # print(ret) #24期出版社 # 查询一下 24期出版社出版过哪些书 # obj = models.Publish.objects.filter(name='24期出版社').first() # # ret = obj.book_set.all() #<QuerySet [<Book: 母猪的产后护理>, <Book: 海狗的怂逼人生>]> # for i in ret: # print(i.title) # 多对多 # 海狗的怂逼人生 是哪些作者写的 -- 正向查询 # 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) # return HttpResponse('ok')
示例:
# 一对一 # 查询一下王洋的电话号码 # ret = models.Author.objects.filter(name='王洋').values('au__telephone') # ret = models.AuthorDetail.objects.filter(author__name='王洋').values('telephone') # print(ret) #<QuerySet [{'au__telephone': '110'}]> #<QuerySet [{'telephone': '110'}]> # # 一对多 # 海狗的怂逼人生这本书是哪个出版社出版的 # ret = models.Book.objects.filter(title='海狗的怂逼人生').values('publishs__name') # print(ret) #<QuerySet [{'publishs__name': '24期出版社'}]> # ret = models.Publish.objects.filter(book__title='海狗的怂逼人生').values('name') # print(ret) #<QuerySet [{'name': '24期出版社'}]> #查询一下24期出版社出版了哪些书 # ret = models.Publish.objects.filter(name='24期出版社').values('book__title') # print(ret) #<QuerySet [{'book__title': '华丽的产后护理'}, {'book__title': '海狗的怂逼人生'}]> # ret = models.Book.objects.filter(publishs__name='24期出版社').values('title') # print(ret) #<QuerySet [{'title': '华丽的产后护理'}, {'title': '海狗的怂逼人生'}]> # 多对多 #海狗的怂逼人生 是哪些作者写的 # ret = models.Book.objects.filter(title='海狗的怂逼人生').values('authors__name') # print(ret) # ret = models.Author.objects.filter(book__title='海狗的怂逼人生').values('name') # print(ret) #<QuerySet [{'name': '王洋'}, {'name': '海狗'}]> # return render(request,'index.txt',{'x':123,'y':456}) # related_name # 查询一下24期出版社出版了哪些书 ret = models.Publish.objects.filter(name='24期出版社').values('xxx__title') #xxx代替反向查询的小写表名 print(ret)
聚合查询 [`æɡrɪɡeɪt]
ret = models.Book.objects.all().aggregate(a=Avg('price'),m=Max('price')) print(ret) 有别名 #{'a': 45.1, 'm': Decimal('200.00')} 无别名 #{'price__avg': 45.1, 'price__max': Decimal('200.00')} # python字典格式,也就是说,聚合查询是orm语句的结束
分组查询
# 每个出版社出版的书的平均价格 # 用的是publish表的id字段进行分组 # ret = models.Book.objects.values('publishs__id').annotate(a=Avg('price')) # 用的book表的publishs_id字段进行分组 # ret = models.Book.objects.values('publishs_id').annotate(a=Avg('price')) # print(ret) # ret = models.Publish.objects.annotate(a=Avg('book__price')).values('a') # print(ret) #<QuerySet [{'a': None}, {'a': 71.166667}, {'a': 6.0}]>
F查询
from django.db.models import Avg, Sum, Max, Min, Count,F # 查询一下评论数大于点赞数的书 ret = models.Book.objects.filter(comment__gt=F('good')) print(ret) # 将所有书的价格上调100块 models.Book.objects.all().update( price=F('price')+100 ) # 引申 同时在char字段后边添加文字 from django.db.models.functions import Concat from django.db.models import Value models.Book.objects.all().update(title=Concat(F("title"), Value("("), Value("第一版"), Value(")")))
Q查询
与 & 或 | 非 ~
from django.db.models import Avg, Sum, Max, Min, Count, F,Q ret = models.Book.objects.filter(Q(id=2)&Q(Q(price__gt=112)|~Q(comment__lte=200))) print(ret)
views
from django.shortcuts import render,HttpResponse,redirect from app01 import models from django.db.models import Avg,Sum,Max,Min,Count,F,Q # Create your views here. def index(request): #1.增加 一对一 # models.AuthorDetail.objects.create( # birthday="2000-11-11", # telephone="555", # addr="美国", # ) # au_obj = models.AuthorDetail.objects.get(id=5) # models.Author.objects.create( # name="海王", # age=66, # au_id=5, # #或者 au="au_obj" # ) # 2. 一对多 书籍和出版社 # pub_obj = models.Publish.objects.get(id=3) # # models.Book.objects.create( # title="xx2", # price=33, # publishDate="2011-11-12", # comment=324, # good=444, # publishes=pub_obj, #类属性作为关键字时,值为model对象 # # publishes_id=3, # 如果关键字为数据库字段名称,那么值为关联数据的值 # ) # 3. 多对多 书籍和作者 # sese = models.Author.objects.get(id=1) # xingxing = models.Author.objects.get(id=2) # # new_obj = models.Book.objects.create( # title="海贼王", # price="45", # publishDate="2009-11-14", # comment=399, # good=666, # publishes_id=2, # ) # 三种方法 # new_obj.authors.add(*[1,2]) #用的最多 # new_obj.authors.add(1,2) # new_obj.authors.add(sese,xingxing) # 4. 删除 一对一 # models.AuthorDetail.objects.filter(id=5).delete() # models.Author.objects.filter(id=4).delete() # 5. 删除 一对多 # models.Publish.objects.filter(id=4).delete() # models.Book.objects.filter(id=4).delete() # 6.删除 多对多 # book_obj = models.Book.objects.get(id=8) # # book_obj.authors.add() #添加 # book_obj.authors.remove(1) # 删除作者1,书籍8 # book_obj.authors.clear() #清除关系 # book_obj.authors.set(["3","4"]) #先清除再添加 # 7. 改 修改书籍名和出版社 # ret = models.Publish.objects.get(id=2) # models.Book.objects.filter(id=7).update( # title="ooo", # publishes=ret, # # publishes_id=2 # ) # 8. 基于对象的跨表查询 一对一 # 关系属性写在表1,关联到表2,那么通过表1的数据去找表2的数据,叫做正向查询,返过来就是反向查询 # 正向查询用对象.属性,反向查询用对象.小写的表名 # 1.查询韩星的电话号 str原因 # obj = models.Author.objects.filter(name="韩星").first() # print(type(obj)) # ph = obj.au.telephone # print(ph) # 反向查询已知电话444,查作者 # obj = models.AuthorDetail.objects.filter(telephone=444).first() # pa = obj.author.name # print(pa) # 9. 基于对象的跨表查询 一对多 # 已知书籍名,查询出版社,正向 # obj = models.Book.objects.filter(title="大主宰").first() # ph = obj.publishes.name # print(ph) # 已知出版社,查询所有书籍,反向,对象.表名_set.all() # obj = models.Publish.objects.filter(name="24期出版社").first() # ret = obj.book_set.all() # <QuerySet [<Book: 风云>, <Book: 莽荒纪>, <Book: ooo>, <Book: 海贼王>]> # print(ret) # for i in ret: # print(i.title) # 10.多对多 # 已知书籍名,查询作者,正向查询 # obj = models.Book.objects.filter(title="万剑道尊").first() # ret = obj.authors.all() #<QuerySet [<Author: 邸宗超>, <Author: 韩星>, <Author: 李文宝>]> # for i in ret: # print(i.name) # print(i.au.telephone) #连环查询,有对象,正向查询 # 已知作者名,查看书籍 # obj = models.Author.objects.filter(name="韩星").first() # ret = obj.book_set.all() # print(ret) #<QuerySet [<Book: 朝花夕拾>, <Book: 浮云>, <Book: 大主宰>, <Book: 万剑道尊>]> # for i in ret: # print(i.title) # 11. 基于双下划线的跨表查询 # 一对一 正向 # 已知作者名,查询电话号 # ret1 = models.Author.objects.filter(name="韩星").values("au__telephone") # print(ret1) #<QuerySet [{'au__telephone': '222'}]> # ret2 = models.AuthorDetail.objects.filter(author__name="韩星").values("telephone") # print(ret2) #<QuerySet [{'telephone': '222'}]> # for i in ret1: # print(i["au__telephone"]) # for j in ret2: # print(j["telephone"]) # 一对多 # 已知书名查询出版社 # ret1 = models.Book.objects.filter(title="大主宰").values("publishes__name") # print(ret1) # <QuerySet [{'publishes__name': '老男人出版社'}]> # ret2 = models.Publish.objects.filter(book__title="大主宰").values("name") # print(ret2) # <QuerySet [{'name': '老男人出版社'}]> # for i in ret1: # print(i["publishes__name"]) # for j in ret2: # print(j["name"]) # 已知出版社,查询书籍名 # ret1 = models.Publish.objects.filter(name="24期出版社").values("book__title") # print(ret1) # ret2 = models.Book.objects.filter(publishes__name="24期出版社").values("title") # print(ret2) # for i in ret1: # print(i["book__title"]) # for j in ret2: # print(j["title"]) # 多对多 # 已知书籍名,查询作者 # ret1 = models.Book.objects.filter(title="万剑道尊").values("authors__name") # print(ret1) # ret2 = models.Author.objects.filter(book__title="万剑道尊").values("name") # print(ret2) # for i in ret1: # print(i["authors__name"]) # 12. 聚合查询 # 统计所有书籍的平均价格,别名可以不写 # ret1 = models.Book.objects.all().aggregate(a=Avg("price"),m=Max("price")) # print(ret1) # 每个出版社出版书的平均价格 # 1.根据publish表的id字段进行分组,别名可以不写 # ret1 = models.Book.objects.values("publishes__id").annotate(a=Avg("price")) # print(ret1) # 2. 根据book的publishs_id字段进行分组,等同于publishes # ret2 = models.Book.objects.values("publishes_id").annotate(a=Avg("price")) # print(ret2) # ret3 = models.Book.objects.values("publishes","id").annotate(a=Avg("price")) # print(ret3) #多条件分组 # 此方法连表查询(book__price),查询的值是a,默认用publish的id分组 # ret4 = models.Publish.objects.annotate(a=Avg("book__price")).values("a") # print(ret4) # F查询 #查询一下评论数大于点赞数的书 # ret = models.Book.objects.all() # l1 = [] # for i in ret: # if i.comment > i.good: # l1.append(i) # for j in l1: # print(j.title) # 双下方法 # ret = models.Book.objects.filter(comment__gt=F("good")) # print(ret) # for i in ret: # print(i.title) #将所有的书籍价格上调100块 # ret = models.Book.objects.all() # for i in ret: # i.price += 100 # i.save() # models.Book.objects.all().update( # price=F("price") - 100 # ) # Q查询 或 | 与 & 非~ # 查询书籍价格大于80并且评论数大于等于200 # ret = models.Book.objects.filter(price__gt=80,comment__gte=200) #和, # print(ret) # 查询书籍价格大于80或者评论数大于等于600 # ret = models.Book.objects.filter(Q(price__gt=80)|Q(comment__gte=600)) # print(ret) #查询id=2,书籍价格大于80或者评论数大于等于600 # ret = models.Book.objects.filter(Q(Q(price__gt=80)|Q(comment__gte=600))&Q(id=2)) # print(ret) # 1 查询每个作者的姓名以及出版的书的最高价格 # ret1 = models.Author.objects.values("name").annotate(m=Max("book__price")) # print(ret1) # ret2 = models.Book.objects.values("authors__name").annotate(Max("price")) # print(ret2) #有点小错误 # 2 查询作者id大于2作者的姓名以及出版的书的最高价格 # ret1 = models.Author.objects.filter(id__gt=2).annotate(m=Max("book__price")).values("name","m") # print(ret1) # 3 查询作者id大于2或者作者年龄大于等于20岁的女作者的姓名以及出版的书的最高价格 # 不对,等于不用Q,直接逗号 # ret1 = models.Author.objects.filter(Q(id__gt=2)|Q(age__gte=20)&Q(sex="female")).annotate(m=Max("book__price")).values("sex","m") # ret1 = models.Author.objects.filter(Q(id__gt=2)|Q(age__gte=20),sex="female").annotate(m=Max("book__price")).values("sex","m") # print(ret1) # 4 查询每个作者出版的书的最高价格的平均值 # ret1 = models.Author.objects.values("name").annotate(m=Max("book__price")).aggregate(a=Avg('m')) # # ret1 = models.Author.objects.annotate(m=Max("book__price")).aggregate(a=Avg('m')) # 默认id分组 # print(ret1) # 5 每个作者出版的所有书的最高价格以及最高价格的那本书的名称 ret1 = models.Author.objects.annotate(m=Max("book__price")).values("name","m") print(ret1) return HttpResponse("OK")
将orm转换为sql语句
# 将下述代码放入settings中 LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console':{ 'level':'DEBUG', 'class':'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'handlers': ['console'], 'propagate': True, 'level':'DEBUG', }, } }
事务
from django.db import transaction # 注意try的位置是在事物的外部,在内部时报错前会对数据库进行修改,不符合事物的特点 try: with transaction.atomic(): # 一系列的操作 models.Book.objects.update(publisher_id=4) models.Book.objects.update(publisher_id=3) int('ss') models.Book.objects.update(publisher_id=2) models.Book.objects.update(publisher_id=5) except Exception as e: print(e)
在Python脚本中调用Django环境
1. 在项目下创建文件夹,并创建py文件 2.输入以下代码 import os # 将数据库路径导入 # 外部文件执行数据库命令,注意修改路径 # os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_orm.settings") os.environ.setdefault("DJANGO_SETTINGS_MODULE", "homework.settings") import django # 导入django django.setup() # 启动django运行程序 from app01 import models # 导入models模块 # 写逻辑代码查询即可,已连接了Django环境
关于别名
publishers = models.ForeignKey(to="Publisher",related_name='books',related_query_name='xx') 关联字段中有此属性时,models.Publisher.objects.filter(xx__title="谁是谁")用到表名小写时替换,优先级 related_query_name 》 related_name 》 表名小写 author__title