聚合查询
聚合查询是指一个数据表中的一个字段的数据进行部分或者全部进行统计查询,查询book数据表中的全部书的平均价格,查询所有书的总数等都需要聚合查询。
- 整表聚合
导入方式:from django.db.models import *
聚合函数:Sum, Avg, Count, Max, Min
语法:MyModel.objects.aggregate(结果变量名= 聚合函数(“列”))
返回结果:结果变量名和值形成的字典,{‘结果变量名’:值}
>>> from django.db.models import *
>>> Book.objects.aggregate(Summary = Sum('price') )
{'Summary': Decimal('170.00')}
>>> Book.objects.aggregate(Summary = Avg('price') )
{'Summary': Decimal('56.666667')}
- 分组聚合
分组聚合是指通过计算查询结果中每一个对象所关联的对象集合,从而得出总计值,即为查询集的每一项生成的聚合
语法:QuerySet.annotate(结果变量名=聚合函数(‘列’))
返回值:QuerySet
步骤:- 通过先用查询结果MyModel.objects.values查找查询要分组的列,MyModel.objects.values(‘列1’,‘列2’),得到一个QuerySet
- 通过返回结果的QuerySet.annotate方法分组聚合得到分组结果
>>> books = Book.objects.values('pub','is_active')
>>> books
<QuerySet [{'pub': '清华大学出版社', 'is_active': True}, {'pub': '机械工业出版社', 'is_a
ctive': True}, {'pub': '清华大学出版社', 'is_active': True}]>
>>> books.annotate(myCount = Count('pub'))
<QuerySet [{'pub': '清华大学出版社', 'is_active': True, 'myCount': 2}, {'pub': '机械工业
出版社', 'is_active': True, 'myCount': 1}]>
>>> books.annotate(active_count = Count('is_active'))
<QuerySet [{'pub': '清华大学出版社', 'is_active': True, 'active_count': 2}, {'pub': '机
械工业出版社', 'is_active': True, 'active_count': 1}]>
>>> books.annotate(myCount = Count('pub')).filter(myCount__gt=1)
<QuerySet [{'pub': '清华大学出版社', 'is_active': True, 'myCount': 2}]>
原生数据库操作
Django也可以支持直接用sql语句的方式通信数据库
查询:使用MyModel.objects.raw()进行数据库查询操作查询
语法:MyModel.objects.raw(sql语句,拼接参数)
返回值:RawQuerySet集合对象【只支持基础操作,如循环】
>>> books = Book.objects.raw('select * from book')
>>> books
<RawQuerySet: select * from book>
>>> for book in books:
... print(book)
...
Django_清华大学出版社_70.00_75.00
Linux_机械工业出版社_80.00_65.00
Python_清华大学出版社_20.00_25.00
完全跨过模型类操作数据库 - 查询/更新/删除
- 导入cursor所在的包
from django.db import connection - 用创建cursor类的构造函数创建cursor对象,再使用cursor对象,为保证在出现异常时能释放cursor资源,通常使用with语句进行创建操作
语法:
from django.db import connection
with connection.cursor() as cur:
cur.execute(‘执行sql语句’,‘拼接参数’)
admin管理后台
django提供了比较完善的后台管理数据库的接口,可供开发过程中的调试和测试使用
django会搜集所有已注册的模型类,为这些模型类提供数据管理界面,供开发者使用
创建后台管理账号python manage.py createsuperuser
注册自定义模型类
注册步骤:
1. 在应用app中的admin.py中导入注册要管理的模型models类
2. 调用admin.site.register方法进行注册,如admin.site.register(自定义模型类)
模型管理器类
作用:为后台管理界面添加便于操作的新功能
模型管理器类需要继承django.contrib.admin里的ModelAdmin类
使用方法:
-
在<应用app>/admin.py中定义模型管理器类
class xxxManage(admin.ModelAdmin): -
绑定注册管理器和模型类
from django.contrib import admin
from .models import *
admin.site.register(YYYY , XXXXManager) # 绑定YYYY模型类 和 XXXXManager管理器类
绑定前:按照Book模型类中__str__中定义的格式输出
绑定后:
from django.contrib import admin
from .models import *
class BookManager(admin.ModelAdmin):
# 列表页显示哪些字段的列
list_display = ['id', 'title', 'pub', 'price', 'market_price', 'info']
# 控制list_display中的字段,那些可以链接到修改页
# 点击title就可以链接到修改页面
list_display_links = ['title']
# 添加过滤器
list_filter = ['pub']
# 添加搜索框【模糊查询】
search_fields = ['title']
# 添加可以在列表页编辑的字段
list_editable = ['price']
class AuthorManager(admin.ModelAdmin):
list_display = ['id', 'name', 'age', 'email']
# Register your models here.
admin.site.register(Book,BookManager)
admin.site.register(Author, AuthorManager)
- list_display 去控制哪些字段会显示在Admin的修改列表页面中
- list_display_links 可以控制list_display中的字段是否应该链接到对象的“修改”页面
- list_filter 设置激活Admin 修改列表页面右侧栏中的过滤器
- search_fields 设置启用Admin 更改列表页面上的搜索框
- list_editable 设置为模型上字段名称列表,将允许在更改列表页面上进行编辑
Meta类
class Book(models.Model):
title = models.CharField("书名", max_length=50, default='', unique=True)
pub = models.CharField("出版社", max_length=100, default='')
price = models.DecimalField("图书定价", max_digits=7, decimal_places=2, default=0.0)
market_price = models.DecimalField("图书零售价", max_digits=7, decimal_places=2, default=0.0)
info = models.CharField("书籍信息", max_length=100, default='', blank=True)
is_active = models.BooleanField("活跃",default=True)
def __str__(self):
return '%s_%s_%s_%s'%(self.title,self.pub,self.price,self.market_price)
class Meta:
db_table = 'book'
# 给模型对象一个易于理解的名称(单数),用于显示在/admin管理界面中
verbose_name = '图书'
# 给模型对象一个易于理解的名称(复数),用于显示在/admin管理界面中
verbose_name_plural = verbose_name
关系映射
一对一映射
一对一是表示现实事务间存在的一对一的对应关系
语法:OneToOneField(类名, on_delete= xxx)级联删除
class A(model.Model):
…
class B(model.Model):
属性 = models.OneToOneField(A, on_delete = xxx)
on_delete 级联删除选项
- models.CASCADE 级联删除。Django模拟SQL约束ON DELETE CASCADE的行为,并删除包含ForeignKey的对象
- models.PROTECT 抛出ProtectError以阻止被引用对象的删除;【等同于mysql默认的RESTRICT】
- SET_NULL设置ForeignKey null; 需要指定null = True
- SET_DEFAULT 将ForeignKey设置为其默认值,必须设置ForeignKey的默认值
// 创建数据
>>> from oto.models import *
>>> author = Author.objects.create(name = 'Wang')
// author 是外键的类,必须对应相同的类对象
>>> wife = Wife.objects.create(name = 'Wife Wang',author = author)
>>> author = Author.objects.create(name = 'Guo')
// author_id 是外键的类属性,必须对应正确的字段值
>>> wife = Wife.objects.create(name = 'Wife Guo',author_id = author.id)
查询:
① 正向查询:直接通过外键属性查询,称为正向查询
>>> wife = Wife.objects.get(name = 'Wife Guo')
>>> print(wife.name,'的老公是',wife.author.name)
Wife Guo 的老公是 Guo
② 反向查询:没有外键的一方,可以通过调用反向属性查询到关联的另一方
反向关联属性为“实例对象.引用类名(小写)”,当反向引用不存在时,会触发异常,若存在,则返回引用类的对象
>>> author = Author.objects.get(id = 1)
>>> author
<Author: Author object (1)>
>>> author.wife
<Wife: Wife object (1)>
>>> print(author.wife.name)
Wife Wang
一对多映射
一对多是表示现实十五之间存在的一对多的对应关系。
一对多需要明确出具体角色,在多表上设置外键。
创建:
class A(models.Model):
…
class B(models.Model):
属性 = models.ForeignKey("…"的模型类, on_delete = xx)
必须指定on_delete的模式
from django.db import models
# Create your models here.
class Publisher(models.Model):
name = models.CharField('名称', max_length=11, unique=True)
class Book(models.Model):
title = models.CharField('书名', max_length=11)
price = models.DecimalField('价格', max_digits=7, decimal_places=2)
pub = models.ForeignKey('Publisher', on_delete=models.CASCADE)
// 创建
>>> from otm.models import *
>>> publisher = Publisher.objects.create(name = '清华大学出版社')
>>> publisher = Publisher.objects.create(name = '北京大学出版社')
>>> book = Book.objects.create(title = 'HTML & CSS',price = 79.80,pub_id = 1)
>>> book = Book.objects.create(title = '数据结构',price = 35,pub_id = 1)
查询:
① 正向查询【通过Book查询Publisher】
>>> from otm.models import *
>>> book = Book.objects.get(id = 1)
>>> book.pub.name
'清华大学出版社'
② 反向查询【通过Publisher查询Book】
反向查询都有一个反向属性为‘多表’_set【小写】,来获得多表中所对应的多个数据对象
>>> pub1 = Publisher.objects.get(id =1)
>>> books = pub1.book_set.all() //
>>> for book in books:
... print(book.title)
...
HTML & CSS
数据结构
>>> books2 = Book.objects.filter(pub = pub1)
>>> for book in books2:
... print(book.title)
...
HTML & CSS
数据结构
多对多映射
多对多表达对象之间多对多复杂关系,如:每个人都有不同的学校(小学,初中,高中),每个学校都有不同的学生
mysql中创建多对多关系需要依赖第三张表来实现
Django中无需手动创建第三张表,Django自动完成
from django.db import models
# Create your models here.
class Author(models.Model):
name = models.CharField('姓名', max_length=11)
class Book(models.Model):
title = models.CharField('书名', max_length=11)
authors = models.ManyToManyField(Author)
// 创建
>>> author1 = Author.objects.get(id =1)
// 反向创建
>>> book11 = author1.book_set.create(title = "Python")
>>> author2 = Author.objects.get(id =2)
>>> author2.book_set.add(book11)
// 正向创建
>>> book = Book.objects.create(title = 'Java')
>>> book.authors.add(author1)
>>> author3 = book.authors.create(name = 'Season')
// 正向查询
>>> book.authors.all()
<QuerySet [<Author: Author object (1)>, <Author: Author object (3)>]>
>>> for author in book.authors.all():
... print(author.name)
...
Ma Zhikai
Season
// 反向查询
>>> author = Author.objects.get(name = 'Ma Zhikai')
>>> books = author.book_set.all()
>>> for book in books:
... print(book.title)
...
Python
Java