文章目录
Django模型层—多表操作
参考:https://www.cnblogs.com/clschao/articles/10439958.html
kafka-python API:https://kafka-python.readthedocs.io/en/master/apidoc/modules.html
三种表关系:一对一、一对多、多对多。
创建模型
# models.py
# 快速运行:
# Tools-->run manage.py Task
from django.db import models
# Create your models here.
from django.db import models
# Create your models here.
class Author(models.Model):
name=models.CharField( max_length=32)
age=models.IntegerField()
authorDetail=models.OneToOneField(to="AuthorDetail",on_delete=models.CASCADE)
# 一对一到详细信息表
# foreign+unique 不写tofield会自动关联主键
# on_delete = models.CASCADE 被关联的键删除后跟它有关联的也都删除了
# on_delete = models.SET_NULL 被关联的删除后,关联的变为空
class AuthorDetail(models.Model):#不常用的放到这个表里面
birthday=models.DateField()
# telephone=models.BigIntegerField()
telephone=models.CharField(max_length=32)
addr=models.CharField( max_length=64)
# 出版社表和书籍表是一对多的关系Forirgn
class Publish(models.Model):
name=models.CharField( max_length=32)
city=models.CharField( max_length=32)
email=models.EmailField() # 实际上是CharField --- 但是后期可以校验格式xx@xx.
class Book(models.Model):
title = models.CharField( max_length=32)
publishDate=models.DateField()
price=models.DecimalField(max_digits=5,decimal_places=2)
# 与Publish建立一对多的关系,外键字段建立在多的一方,字段publish如果是外键字段,那么它自动是int类型
publishs=models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE)
# foreign key(publish) references publish(id)
authors=models.ManyToManyField(to='Author',) # author不是表的字段,知识类的一个属性,用来操作下边的第三张表,写在被关联的那张表里也可以
# manytomany会自动生成下边这样一张表,如果还有其他字段可以手动创建这张表
# class BookToAuthor(models.Model):
# book_id = models.ForeignKey(to="Book",to_field="id",on_delete=models.CASCADE)
# author_id = models.ForeignKey(to="Author",to_field="id",on_delete=models.CASCADE)
Django–admin
1. 创建一个超级用户,密码不能低于8位
manage.py@manytable > createsuperuser
"C:\Program Files\JetBrains\PyCharm20190301\bin\runnerw64.exe" C:\Users\libo\AppData\Local\Programs\Python\Python36\python.exe "C:\Program Files\JetBrains\PyCharm20190301\plugins\python\helpers\pycharm\django_manage.py" createsuperuser D:/django_projects/manytable
Tracking file by folder pattern: migrations
Username (leave blank to use 'libo'): laowang
Email address:
Warning: Password input may be echoed.
Password: laowang123456
Warning: Password input may be echoed.
Password (again): laowang123456
Superuser created successfully.
2. admin.py文件中注册你的表到admin后台中
from django.contrib import admin
from app01 import models
# Register your models here.
admin.site.register(models.Book)
admin.site.register(models.Publish)
admin.site.register(models.Author)
admin.site.register(models.AuthorDetail)
3. 浏览器访问http://127.0.0.1:8000/admin
登录你的超级用户后就有图形界面,点击相应按钮来操作你的表
views.py通过models操作
增
from django.shortcuts import render,HttpResponse,redirect
from app01 import models
# Create your views here.
def query(request):
# 增
# 一对一增加
new_author_detail = models.AuthorDetail.objects.create(
birthday='1979-08-08',
telephone='13456789876',
addr='黑龙江哈尔滨',
)
# 方式1
models.Author.objects.create(
name='卡特',
age=18,
authorDetail=new_author_detail,
)
# 方式2 常用
obj = models.AuthorDetail.objects.filter(addr='陕西临汾').first()
models.Author.objects.create(
name='卡特',
age=18,
authorDetail_id=obj.id,
)
# 一对多
# 方式1
models.Book.objects.create(
title='祖安快嘴练习生',
publishDate='2019-08-09',
price=3,
publishs=models.Publish.objects.get(id=1),
)
# 方式2 常用
models.Book.objects.create(
title='祖安快嘴练习生2',
publishDate='2019-08-09',
price=3,
publishs_id=models.Publish.objects.get(id=1).id,
)
# 多对多
# 方式1 常用
book_obj = models.Book.objects.get(id=1)
book_obj.authors.add(*[1, 2])
# 方式2
author1 = models.Author.objects.get(id=1)
author2 = models.Author.objects.get(id=3)
book_obj_ = models.Book.objects.get(id=5)
book_obj_.authors.add(*[author1, author2])
return HttpResponse('ok')
删除
# 删除
# 一对一和多对一的情况和单表删除的操作相同
# 一对一
# author也会跟着级联删除
models.AuthorDetail.objects.get(id=2).delete()
# 删除author对AuthorDetail没有影响
models.Author.objects.get(id=1).delete()
# 一对多
# 删出版社,这个出版社下边的书全部被级联删除
models.Publish.objects.get(id=1).delete()
# 删除某本书,不会对出版社有影响
models.Book.objects.get(id=2).delete()
# 多对多
# 删除id为3的那本书的作者里边id为4和5的作者,就是id=3的书没有作者4和5了,书还在,作者也在,知识删掉自动生成的 book_author那张表里的记录
book_obj_1 = models.Book.objects.get(id=3)
book_obj_1.authors.remove(*[4, 5])
# 方式2就是找到作者对象,放进列表去
book_obj_1.authors.clear() # 把id=3的对应的作者记录全删了
book_obj_1.authors.set(['5', '6']) # 先清空,再添加个5和6
更新
# 更新
# 一对一
# 把id=2的作者新更改
models.Author.objects.filter(id=2).update(
name='厄加特',
age=18,
# authorDetail=models.AuthorDetail.objects.get(id=5),
authorDetail_id=5, # 两种方式
)
# 一对多
# 把id=4的书的出版社改为3的出版社
models.Book.objects.filter(pk=4).update( # pk表的主键字段
title='B哥往事',
# publishs=models.Publish.objects.get(id=3),
publishs_id=3, # 两种方式
)
# 不会做级联更新,orm没有级联更新,可以在mysql中级联更新,自查
查询
基于对象的跨表查询 – 类似于子查询
正向查询和反向查询
通过设立约束关系的表想被约束关系的表查询是正向查询–从大腿想孩子查
反过来查就是反向查询
正向查询:关系属性(字段)卸载哪个类(表)里边,从当前类(表)的数据去查询它的关联类(表)的数据。
反向查询:反之。
# 一对一
# 正向查询
# 查询盖伦的住址
author_obj = models.Author.objects.filter(name='盖伦').first()
print(author_obj.authDetail.addr) # 盖伦的那一条AuthorDetail
# 反向查询
# 查询444这个电话号是谁的?
author_detail_obj = models.AuthorDetail.objects.get(telephone='444')
print(author_detail_obj.author.name)
# Author ---------> AuthorDetail 正向查询 author_obj.authDetail.addr, 对象.关联名称
# Author <--------- AuthorDetail 反向查询 author_detail_obj.author.name,对象.小写类名
# 一对多
# 正向查询
# 查询一下 李帅的床头故事 这本书的出版社是哪个
book_obj = models.Book.objects.get(title='李帅的床头故事')
print(book_obj.publishs.name) # B哥出版社
# 反向查询
# B哥出版社出版了哪些书?
pub_obj = models.Publish.objects.get(name='B哥出版社')
print(pub_obj.book_set.all()) # 一对多,反向找,可能会找到多个,所以加set,结果是QuerySet
# Book -----------> Publish 正向查询 book_obj.publishs.name 对象.属性
# Book <----------- Publish 反向查询 pub_obj.book_set.all() 对象.小写类名_set
# 多对多
# 正向查询
# 李帅的床头故事 这本书是谁写的?
book_obj = models.Book.objects.get(title='李帅的床头故事')
print(book_obj.authors.all())
# 反向查询
# 盖伦写了哪些书?
author_obj = models.Author.objects.get(name='盖伦')
print(author_obj.book_set.all())
# Book ---------------> Author 正向查询 book_obj.authors.all() 对象.属性
# Book <--------------- Author 反向查询 pub_obj.book_set.all() 对象.小写类名_set
基于双下划线的跨表查询
# 基于双下划线的跨表查询 联表 效率高
# 一对一
# 1.查询盖伦的电话号
# 方式1 正向
obj = models.Author.objects.filter(name='盖伦').values('authorDetail__telephone')
print(obj) # QuerySet类型
# 方式2 反向
obj = models.AuthorDetail.objects.filter(author__name='盖伦').values('telephone', 'author__age')
print(obj) # QuerySet类型
# 2.查询哪个老师的电话是444?
# 正向
obj = models.Author.objects.filter(authorDetail__telephone='444').values('name')
print(obj)
# 反向查询
obj = models.AuthorDetail.objects.filter(telephone='444').values('author__name')
print(obj)
# 一对多
# 查询一下 李帅的床头故事 这本书的出版社是哪个?
obj = models.Book.objects.filter(title='李帅的床头故事').values('publishs__name')
print(obj)
obj = models.Publish.objects.filter(book__title='李帅的床头故事').values('name')
print(obj)
# B哥出版社都出版了那些书?
obj = models.Publish.objects.filter(name='B哥出版社').values('book__title')
print(obj)
obj = models.Book.objects.filter(publishs__name='B哥出版社').values('title')
print(obj)
# 多对多
# 李帅的床头故事 这本书是谁写的?
obj = models.Book.objects.filter(title='李帅的床头故事').values('authors__name')
print(obj)
obj = models.Author.objects.filter(book__title='李帅的床头故事').values('name')
print(obj)
# 盖伦写了那些书
obj = models.Book.objects.filter(authors__name='盖伦').values('title')
print(obj)
obj = models.Author.objects.filter(name='盖伦').values('book__title')
print(obj)
进阶的查询
# 进阶的查询
# 查询B哥出版社出版的书的名称以及作者的名字?
obj = models.Book.objects.filter(publishs__name='B哥出版社').values('title','authors__name')
print(obj)
# 手机号以4开头的作者出版过的所有书籍名称以及出版社名称
# Author AuthorDetail Book Publish
obj = models.Author.objects.filter(authorDetail__telephone__startswith='4').values('book__title', 'book__publishs__name')
print(obj)
# models.py里的calss里,外键起别名
# publishs=models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE,related_name='xxx') # 反向查询的时候不用写表名了,直接写xxx即可,再写表名就会报错,正向不影响
# 同样的manytomany也有
聚合查询
from django.db.models import Avg, Aggregate, Max, Min, Sum, Count
# 计算所有图书的平均价格
obj = models.Book.objects.all().aggregate(a=Avg('price'), m=Max('price'))
print(obj) # {'a': 55.95, 'm': Decimal('200.00')} 所有书的价格平均值 返回的是键值对 后边不能在跟任何表操作语句
分组查询
# 分组查询
# 统计每个出版社出版的书籍的平均价格
ret = models.Book.objects.values('publishs_id').annotate(a=Avg('price'))
print(ret) # <QuerySet [{'publishs_id': 1, 'a': 10.9}, {'publishs_id': 2, 'a': 200.0}, {'publishs_id': 3, 'a': 2.0}]>
# select avg(price) from app01_book group by publishs_id;
ret = models.Publish.objects.annotate(a=Avg('book__price')).values('name', 'a')
print(ret) # <QuerySet [{'name': '老男人出版社', 'a': 10.9}, {'name': '妹妹出版社', 'a': 200.0}, {'name': '各个出版社', 'a': 2.0}]>
F查询
在上面所有的例子中,我们构造的过滤器都只是将字段值与某个常量做比较。如果我们要对两个字段的值做比较,那该怎么做呢?我们在book表里面加上两个字段:评论数:commentNum,收藏数:KeepNum
Django 提供 F() 来做这样的比较。F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。
# F查询
from django.db.models import F, Q
# 点赞数大于评论数的数据
ret = models.Book.objects.filter(good__gt=F('comment'))
# 查询评论数大于收藏数2倍的书籍
Book.objects.filter(commentNum__lt=F('keepNum')*2)
# 修改操作也可以使用F函数,比如将每一本书的价格提高30元:
Book.objects.all().update(price=F("price")+30)
Q查询
# ` filter()` 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如`OR` 语句),你可以使用`Q 对象`。
from django.db.models import Q
Q(title__startswith='Py')
# Q 对象可以使用&(与) 、|(或)、~(非) 操作符组合起来。当一个操作符在两个Q 对象上使用时,它产生一个新的Q 对象。
bookList=Book.objects.filter(Q(authors__name="yuan")|Q(authors__name="egon"))
# WHERE name ="yuan" OR name ="egon"