ORM 是个啥?

在python中的一个默认的编写规范是一切皆对象,这样做使得代码简洁,结构清晰,便于维护和重用代码,同时极大的提升开发效率。

同样在操作数据库时,一般我们用SQL语句来实现操作,但是放在Python中是一串冗长的字符串,不利于调试和修改,更不符合上面提到的规范。

所以,有大佬就提出ORM来替代原生的SQL语句,说白了ORM 就是要给缩写,代表着 对象-关系-映射

简写 全称 中文
O Object 对象
R Relational 关系
M Mapping 映射

有了ORM,我们来看它与实际的数据库是怎么联系起来的:

mark

数据库 ORM
数据库的表(table ) 类(class)
记录,行数据(record) 对象(object)
字段(field) 对象的属性(attribute)

ORM相对原始SQL的优劣势

  • 优势
    • 专注业务逻辑开发,提升开发效率
    • 易于更新维护,重用代码
    • 会自动完成比如数据消毒,预处理,事务等功能
    • 不用编写复杂的SQL语句
  • 劣势
    • 牺牲执行效率,增加查询时间
    • 无法操作底层数据库,无法实现某些复杂操作
    • 遗忘SQL语句编写

怎么选择原生SQL和ORM

  • 对于复杂的SQL语句或数据库层面,推荐使用原始SQL
  • 对于要处理复杂的业务逻辑,加快开发,推荐使用ORM
  • ORM 相对 原始SQL在一般的业务中,损耗其实并不高,可以忽略不计

开发前准备

新建项目

mark

配置数据库

mark

配置模型

mark

字段类型和参数

常用字段

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author : Baimoc
# @Email : baimoc@163.com
# @Time : 2020/7/24 9:45

from django.db import models


class Field(models.Model):
# 自增字段
Auto = models.AutoField()
# 自增字段,最大值可拓展到更大
BigAuto = models.BigAutoField()

# 二进制数据
Binary = models.BinaryField()

# 布尔型
Boolean = models.BooleanField()
NullBoolean = models.NullBooleanField() # 允许为空的布尔型

# 整型
PositiveSmallInterger = models.PositiveSmallIntegerField() # 长度为 5字节正整数
SmallIntegerField = models.SmallIntegerField() # 长度为 6字节整数
PositiveIntegerField = models.PositiveIntegerField() # 长度为 10字节正整数
IntegerField = models.IntegerField() # 长度为 11字节正整数
BigIntegerField = models.BigIntegerField() # 长度为 20字节正整数

# 字符串类型
Char = models.CharField() # varchar
Text = models.TextField() # longtext

# 时间日期类型
Date = models.DateField() # 年月日
DateTime = models.DateTimeField() # 年月日时分秒
Duration = models.DurationField() # int,Python timedelta实现

# 浮点型
Float = models.FloatField()
Decimal = models.DecimalField() # 需要指定整数或小数有多少位

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author : Baimoc
# @Email : baimoc@163.com
# @Time : 2020/7/24 9:45

from django.db import models


class Field(models.Model):
# 自增字段
Auto = models.AutoField()
# 自增字段,最大值可拓展到更大
BigAuto = models.BigAutoField()

# 二进制数据
Binary = models.BinaryField()

# 布尔型
Boolean = models.BooleanField()
NullBoolean = models.NullBooleanField() # 允许为空的布尔型

# 整型
PositiveSmallInterger = models.PositiveSmallIntegerField() # 长度为 5字节正整数
SmallIntegerField = models.SmallIntegerField() # 长度为 6字节整数
PositiveIntegerField = models.PositiveIntegerField() # 长度为 10字节正整数
IntegerField = models.IntegerField() # 长度为 11字节正整数
BigIntegerField = models.BigIntegerField() # 长度为 20字节正整数

# 字符串类型
Char = models.CharField() # varchar
Text = models.TextField() # longtext

# 时间日期类型
Date = models.DateField() # 年月日
DateTime = models.DateTimeField() # 年月日时分秒
Duration = models.DurationField() # int,Python timedelta实现

# 浮点型
Float = models.FloatField()
Decimal = models.DecimalField() # 需要指定整数或小数有多少位

# 高级字段
Email = models.EmailField()
Image = models.ImageField()
File = models.FileField()
FilePath = models.FilePathField()
URL = models.URLField()
UUID = models.UUIDField()

关系型字段

一对一(OneToOneField)

多对一(ForeignKey)

多对多(ManyToManyField)

class A(models.Model):
one2one = models.OneToOneField(Field)


class B(models.Model):
one2one = models.ForeignKey(A)


class class A(models.Model):
one2one = models.OneToOneField(Field)


class B(models.Model):
one2one = models.ForeignKey(A)


class C(models.Model):
one2one = models.ManyToManyField(B)

字段参数

  • 所有字段都具有的参数
    • db_column:修改字段名
    • primary_key:主键
    • verbose_name:字段别名,备注
    • unique:值是否唯一
    • null:数据空中的值,是否允许为空
    • blank:前端表单提交时,是否可以为空,一般null=True,blank=True
    • db_index:是否建立字段索引
    • help_text:显示帮助
    • editable:后台是否可以编辑
  • 个别字段才有的参数
    • CharField
      • max_length:最大长度值
    • DateField
      • unique_for_date:该日期的值是否唯一
      • unique_for_month:该月份的值是否唯一
      • auto_now=True:更新数据时间
      • auto_now_add=True:插入数据时间
    • DecimalField
      • max_digits:多少位数
      • decimal_places:多少位小数,例子(max_digits=4,decimal_places=2),可以存储11.11,32.55
  • 关系型字段的参数
    • related_name:用于外键关联的反向查询,父表查子表
    • on_delete:当外键被删除时,要进行什么操作

自关联

例子:省市县的存储

class AddressInfo(models.Model):
address = models.CharField(max_length=200, null=True, blank=True, verbose_name="地址")
pid = models.ForeignKey('self', null=True, blank=True, verbose_name='自关联', on_delete=models.CASCADE) # 写法一
# pid = models.ForeignKey('AddressInfo', null=True, blank=True, verbose_name='自关联') # 写法二

def __str__(self):
class AddressInfo(models.Model):
address = models.CharField(max_length=200, null=True, blank=True, verbose_name="地址")
pid = models.ForeignKey('self', null=True, blank=True, verbose_name='自关联', on_delete=models.CASCADE) # 写法一
# pid = models.ForeignKey('AddressInfo', null=True, blank=True, verbose_name='自关联') # 写法二

def __str__(self):
return self.address

元数据

class AddressInfo(models.Model):
address = models.CharField(max_length=200, null=True, blank=True, verbose_name="地址")
pid = models.ForeignKey('self', null=True, blank=True, verbose_name='自关联', on_delete=models.CASCADE) # 写法一
# pid = models.ForeignKey('AddressInfo', null=True, blank=True, verbose_name='自关联') # 写法二
note = models.CharField(max_length=200, null=True, blank=True, verbose_name="说明")

def __str__(self):
return self.address

class Meta:
# 定义数据表名
db_table='address'
# 按照哪个字段排序
# ordering=('pid',)
# 表别名
verbose_name='地址信息'
# 表别名复数,用于英文显示
verbose_name_plural=verbose_name
# 设置基类,不生成数据表,作为其他表的基类
# abstract=False
# 设置表权限
# permissions=(('定义好的权限', '权限说明'),)
# 是否按照Django既定的规则来管理模型类
# managed=False
# 联合唯一键
# unique_together=('address', 'note') # 另一种写法 ((),())
# 定义模型类属于哪个应用
class AddressInfo(models.Model):
address = models.CharField(max_length=200, null=True, blank=True, verbose_name="地址")
pid = models.ForeignKey('self', null=True, blank=True, verbose_name='自关联', on_delete=models.CASCADE) # 写法一
# pid = models.ForeignKey('AddressInfo', null=True, blank=True, verbose_name='自关联') # 写法二
note = models.CharField(max_length=200, null=True, blank=True, verbose_name="说明")

def __str__(self):
return self.address

class Meta:
# 定义数据表名
db_table='address'
# 按照哪个字段排序
# ordering=('pid',)
# 表别名
verbose_name='地址信息'
# 表别名复数,用于英文显示
verbose_name_plural=verbose_name
# 设置基类,不生成数据表,作为其他表的基类
# abstract=False
# 设置表权限
# permissions=(('定义好的权限', '权限说明'),)
# 是否按照Django既定的规则来管理模型类
# managed=False
# 联合唯一键
# unique_together=('address', 'note') # 另一种写法 ((),())
# 定义模型类属于哪个应用
# app_label='myapp1

mark

实例

mark

建表

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author : Baimoc
# @Email : baimoc@163.com
# @Time : 2020/7/24 9:45

from django.db import models


class Teacher(models.Model):
"""讲师信息表"""
nickname = models.CharField(max_length=30, primary_key=True, db_index=True, verbose_name="昵称")
introduction = models.TextField(default="这位同学很懒,木有签名", verbose_name="简洁")
fans = models.PositiveIntegerField(default="0", verbose_name="粉丝数")
created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")

class Meta:
verbose_name = "讲师信息表"
verbose_name_plural = verbose_name

def __str__(self):
return self.nickname


class Course(models.Model):
"""课程信息表"""
title = models.CharField(max_length=100, primary_key=True, db_index=True, verbose_name="课程名")
# 老师和课程为多对一关系,使用 ForeignKey 来实现
teacher = models.ForeignKey(Teacher, null=True, on_delete=models.CASCADE, verbose_name="课程讲师")
type = models.CharField(choices=((1, "实战课"), (2, "免费课"), (0, "其他")), max_length=1, default=0, verbose_name="课程类")
price = models.PositiveSmallIntegerField(verbose_name="价格")
volume = models.BigIntegerField(verbose_name="销量")
online = models.DateField(verbose_name="上线时间")
created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")

class Meta:
verbose_name = "课程信息表"
verbose_name_plural = verbose_name

def __str__(self):
# 返回type的描述信息
return f"{self.get_type_display(), self.title}"


class Student(models.Model):
"""学生信息表"""
nickname = models.CharField(max_length=30, primary_key=True, db_index=True, verbose_name="昵称")
# 课程与学生是多对多关系
course = models.ManyToManyField(Course, verbose_name="课程")
age = models.PositiveSmallIntegerField(verbose_name="年龄")
gender = models.CharField(choices=((1, "男"), (2, "女"), (0, "保密")), max_length=1, default=0, verbose_name="性别")
study_time = models.PositiveIntegerField(default="0", verbose_name="学习时长(h)")
created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")

class Meta:
verbose_name = "学生信息表"
verbose_name_plural = verbose_name

def __str__(self):
return self.nickname


class TeacherAssisant(models.Model):
"""助教信息表"""
nickname = models.CharField(max_length=30, primary_key=True, db_index=True, verbose_name="昵称")
teacher = models.OneToOneField(Teacher, null=True, on_delete=models.SET_NULL, verbose_name="讲师")
hobby = models.CharField(max_length=100, null=True, blank=True, verbose_name="爱好")
created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")

class Meta:
verbose_name = "助教信息表"
db_table = "courses_assistant"
verbose_name_plural = verbose_name

def __str__(self):
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author : Baimoc
# @Email : baimoc@163.com
# @Time : 2020/7/24 9:45

from django.db import models


class Teacher(models.Model):
"""讲师信息表"""
nickname = models.CharField(max_length=30, primary_key=True, db_index=True, verbose_name="昵称")
introduction = models.TextField(default="这位同学很懒,木有签名", verbose_name="简洁")
fans = models.PositiveIntegerField(default="0", verbose_name="粉丝数")
created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")

class Meta:
verbose_name = "讲师信息表"
verbose_name_plural = verbose_name

def __str__(self):
return self.nickname


class Course(models.Model):
"""课程信息表"""
title = models.CharField(max_length=100, primary_key=True, db_index=True, verbose_name="课程名")
# 老师和课程为多对一关系,使用 ForeignKey 来实现
teacher = models.ForeignKey(Teacher, null=True, on_delete=models.CASCADE, verbose_name="课程讲师")
type = models.CharField(choices=((1, "实战课"), (2, "免费课"), (0, "其他")), max_length=1, default=0, verbose_name="课程类")
price = models.PositiveSmallIntegerField(verbose_name="价格")
volume = models.BigIntegerField(verbose_name="销量")
online = models.DateField(verbose_name="上线时间")
created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")

class Meta:
verbose_name = "课程信息表"
verbose_name_plural = verbose_name

def __str__(self):
# 返回type的描述信息
return f"{self.get_type_display(), self.title}"


class Student(models.Model):
"""学生信息表"""
nickname = models.CharField(max_length=30, primary_key=True, db_index=True, verbose_name="昵称")
# 课程与学生是多对多关系
course = models.ManyToManyField(Course, verbose_name="课程")
age = models.PositiveSmallIntegerField(verbose_name="年龄")
gender = models.CharField(choices=((1, "男"), (2, "女"), (0, "保密")), max_length=1, default=0, verbose_name="性别")
study_time = models.PositiveIntegerField(default="0", verbose_name="学习时长(h)")
created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")

class Meta:
verbose_name = "学生信息表"
verbose_name_plural = verbose_name

def __str__(self):
return self.nickname


class TeacherAssisant(models.Model):
"""助教信息表"""
nickname = models.CharField(max_length=30, primary_key=True, db_index=True, verbose_name="昵称")
teacher = models.OneToOneField(Teacher, null=True, on_delete=models.SET_NULL, verbose_name="讲师")
hobby = models.CharField(max_length=100, null=True, blank=True, verbose_name="爱好")
created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
updated_at = models.DateTimeField(auto_now=True, verbose_name="更新时间")

class Meta:
verbose_name = "助教信息表"
db_table = "courses_assistant"
verbose_name_plural = verbose_name

def __str__(self):
return self.nickname

mark

更改数据库表

删除模型类的步骤

  • 删除表模型
  • 删除项目中migraions文件夹下模型类生成的对应文件
  • 删除数据库migraions表中的生成记录
  • 删除数据表

导入数据

1.命令行添加

mark

数据库中的数据表

mark

2. 脚本添加
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author : Baimoc
# @Email : baimoc@163.com
# @Time : 2020/7/24 15:29
# @File : orm_data

import os
import sys
import random
import django
from datetime import date

project_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(project_path) # 将项目路径添加到系统搜寻路径当中
os.environ['DJANGO_SETTINGS_MODULE'] = 'orm_baimoc.settings' # 设置项目的配置文件
django.setup()

from ormbaimoc.models import Teacher, Course, Student, TeacherAssisant

def import_data():
"""使用 Django ORM 导入数据"""
# 讲师数据
Teacher.objects.create(nickname="Jack", introduction="Python 工程师", fans=123)
Teacher.objects.create(nickname="Allen", introduction="Java 工程师", fans=321)
Teacher.objects.create(nickname="Henry", introduction="Golang 工程师", fans=888)

# 课程数据
Course.objects.bulk_create([Course(title=f"Python 系列教程{i}",
teacher=Teacher.objects.get(nickname="Jack"),
type=random.choice((0, 1, 2)),
price=random.randint(200,300),
volume=random.randint(100, 10000),
online=date(2018, 10, 1))
for i in range(1, 5)])
Course.objects.bulk_create([Course(title=f"Java 系列教程{i}",
teacher=Teacher.objects.get(nickname="Allen"),
type=random.choice((0, 1, 2)),
price=random.randint(200,300),
volume=random.randint(100, 10000),
online=date(2018, 6, 6))
for i in range(1, 4)])
Course.objects.bulk_create([Course(title=f"Golang 系列教程{i}",
teacher=Teacher.objects.get(nickname="Henry"),
type=random.choice((0, 1, 2)),
price=random.randint(200,300),
volume=random.randint(100, 10000),
online=date(2020, 11, 1))
for i in range(1, 3)])

# 学生数据
Student.objects.update_or_create(nickname="赵同学", defaults={
"age":random.randint(18, 58),
"gender":random.choice((0, 1, 2)),
"study_time":random.randint(9, 999),
})
Student.objects.update_or_create(nickname="吴同学", defaults={
"age": random.randint(18, 58),
"gender": random.choice((0, 1, 2)),
"study_time": random.randint(9, 999),
})
Student.objects.update_or_create(nickname="郑同学", defaults={
"age":random.randint(18, 58),
"gender":random.choice((0, 1, 2)),
"study_time":random.randint(9, 999),
})
Student.objects.update_or_create(nickname="王同学", defaults={
"age": random.randint(18, 58),
"gender": random.choice((0, 1, 2)),
"study_time": random.randint(9, 999),
})

# 正向添加
# 销量大于等于 1000 的课程
Student.objects.get(nickname="赵同学").course.add(*Course.objects.filter(volume__gte=1000))
# 销量大于 5000 的课程
Student.objects.get(nickname="王同学").course.add(*Course.objects.filter(volume__gt=5000))

# 反向添加
# 学习实践大于等于 500 小时的同学
Course.objects.get(title="Python 系列教程1").student_set.add(*Student.objects.filter(study_time__gte=500))
# 学习实践小于等于 500 小时的同学
Course.objects.get(title="Python 系列教程1").student_set.add(*Student.objects.filter(study_time__lte=500))

# 助教数据 get_or_create
TeacherAssisant.objects.get_or_create(nickname="助教1",
defaults={"hobby":"慕课网学习", "teacher":Teacher.objects.get(nickname="Jack")})
TeacherAssisant.objects.get_or_create(nickname="助教2",
defaults={"hobby": "看电影", "teacher": Teacher.objects.get(nickname="Allen")})
TeacherAssisant.objects.get_or_create(nickname="助教3",
defaults={"hobby": "读书", "teacher": Teacher.objects.get(nickname="Henry")})
return True


if __name__ == '__main__':
if import_data():
print("导入数据成功")

# 其他导入数据方法
# fixtures Django serialization 保存
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author : Baimoc
# @Email : baimoc@163.com
# @Time : 2020/7/24 15:29
# @File : orm_data

import os
import sys
import random
import django
from datetime import date

project_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(project_path) # 将项目路径添加到系统搜寻路径当中
os.environ['DJANGO_SETTINGS_MODULE'] = 'orm_baimoc.settings' # 设置项目的配置文件
django.setup()

from ormbaimoc.models import Teacher, Course, Student, TeacherAssisant

def import_data():
"""使用 Django ORM 导入数据"""
# 讲师数据
Teacher.objects.create(nickname="Jack", introduction="Python 工程师", fans=123)
Teacher.objects.create(nickname="Allen", introduction="Java 工程师", fans=321)
Teacher.objects.create(nickname="Henry", introduction="Golang 工程师", fans=888)

# 课程数据
Course.objects.bulk_create([Course(title=f"Python 系列教程{i}",
teacher=Teacher.objects.get(nickname="Jack"),
type=random.choice((0, 1, 2)),
price=random.randint(200,300),
volume=random.randint(100, 10000),
online=date(2018, 10, 1))
for i in range(1, 5)])
Course.objects.bulk_create([Course(title=f"Java 系列教程{i}",
teacher=Teacher.objects.get(nickname="Allen"),
type=random.choice((0, 1, 2)),
price=random.randint(200,300),
volume=random.randint(100, 10000),
online=date(2018, 6, 6))
for i in range(1, 4)])
Course.objects.bulk_create([Course(title=f"Golang 系列教程{i}",
teacher=Teacher.objects.get(nickname="Henry"),
type=random.choice((0, 1, 2)),
price=random.randint(200,300),
volume=random.randint(100, 10000),
online=date(2020, 11, 1))
for i in range(1, 3)])

# 学生数据
Student.objects.update_or_create(nickname="赵同学", defaults={
"age":random.randint(18, 58),
"gender":random.choice((0, 1, 2)),
"study_time":random.randint(9, 999),
})
Student.objects.update_or_create(nickname="吴同学", defaults={
"age": random.randint(18, 58),
"gender": random.choice((0, 1, 2)),
"study_time": random.randint(9, 999),
})
Student.objects.update_or_create(nickname="郑同学", defaults={
"age":random.randint(18, 58),
"gender":random.choice((0, 1, 2)),
"study_time":random.randint(9, 999),
})
Student.objects.update_or_create(nickname="王同学", defaults={
"age": random.randint(18, 58),
"gender": random.choice((0, 1, 2)),
"study_time": random.randint(9, 999),
})

# 正向添加
# 销量大于等于 1000 的课程
Student.objects.get(nickname="赵同学").course.add(*Course.objects.filter(volume__gte=1000))
# 销量大于 5000 的课程
Student.objects.get(nickname="王同学").course.add(*Course.objects.filter(volume__gt=5000))

# 反向添加
# 学习实践大于等于 500 小时的同学
Course.objects.get(title="Python 系列教程1").student_set.add(*Student.objects.filter(study_time__gte=500))
# 学习实践小于等于 500 小时的同学
Course.objects.get(title="Python 系列教程1").student_set.add(*Student.objects.filter(study_time__lte=500))

# 助教数据 get_or_create
TeacherAssisant.objects.get_or_create(nickname="助教1",
defaults={"hobby":"慕课网学习", "teacher":Teacher.objects.get(nickname="Jack")})
TeacherAssisant.objects.get_or_create(nickname="助教2",
defaults={"hobby": "看电影", "teacher": Teacher.objects.get(nickname="Allen")})
TeacherAssisant.objects.get_or_create(nickname="助教3",
defaults={"hobby": "读书", "teacher": Teacher.objects.get(nickname="Henry")})
return True


if __name__ == '__main__':
if import_data():
print("导入数据成功")

# 其他导入数据方法
# fixtures Django serialization 保存
# 数据库层面的导入数据

Model API

基本查询

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author : Baimoc
# @Email : baimoc@163.com
# @Time : 2020/7/26 18:39
# @File : view

from django.shortcuts import render
from django.views.generic import View
from django.http import JsonResponse
from .models import AddressInfo, Teacher, Course,Student,TeacherAssisant


class IndexView(View):
"""主页"""

def get(self, request):
# 查询全部
teachers = Teacher.objects.all()
print(teachers)

# 获取一个值
# 只能返回一条结果,多条会报错
teachers2 = Teacher.objects.get(nickname='Jack')
print(teachers2, type(teachers2))

# 查询符合条件的多个值
# 返回QuerySet,可以是多条结果
teachers3 = Teacher.objects.filter(fans__gte=500)
for teacher in teachers3:
print(f"讲师姓名:{teacher.nickname} --> 粉丝数:{teacher.fans}")

# 字段数据匹配
teacher4 = Teacher.objects.filter(fans__in=[888])
print(teacher4)

# 结果切片
print(Teacher.objects.all()[:2])
# 排序
teacher6 = Teacher.objects.all().order_by('.fans')
for t in teacher6:
print(t.fans)
# 链式查询
teacher7 = Teacher.objects.filter(fans__gte=100).order_by('nickname')
print(teacher7)

# 查询原生SQL
print(Teacher.objects.filter(fans__gte=100).order_by('nickname').query)

return render(request, #!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author : Baimoc
# @Email : baimoc@163.com
# @Time : 2020/7/26 18:39
# @File : view

from django.shortcuts import render
from django.views.generic import View
from django.http import JsonResponse
from .models import AddressInfo, Teacher, Course,Student,TeacherAssisant


class IndexView(View):
"""主页"""

def get(self, request):
# 查询全部
teachers = Teacher.objects.all()
print(teachers)

# 获取一个值
# 只能返回一条结果,多条会报错
teachers2 = Teacher.objects.get(nickname='Jack')
print(teachers2, type(teachers2))

# 查询符合条件的多个值
# 返回QuerySet,可以是多条结果
teachers3 = Teacher.objects.filter(fans__gte=500)
for teacher in teachers3:
print(f"讲师姓名:{teacher.nickname} --> 粉丝数:{teacher.fans}")

# 字段数据匹配
teacher4 = Teacher.objects.filter(fans__in=[888])
print(teacher4)

# 结果切片
print(Teacher.objects.all()[:2])
# 排序
teacher6 = Teacher.objects.all().order_by('.fans')
for t in teacher6:
print(t.fans)
# 链式查询
teacher7 = Teacher.objects.filter(fans__gte=100).order_by('nickname')
print(teacher7)

# 查询原生SQL
print(Teacher.objects.filter(fans__gte=100).order_by('nickname').query)

return render(request, "address.html")

返回新 QuerySet API

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author : Baimoc
# @Email : baimoc@163.com
# @Time : 2020/7/26 18:39
# @File : view
from datetime import date

from django.db.models import Sum, Avg, Max, Min
from django.shortcuts import render
from django.views.generic import View
from django.http import JsonResponse
from .models import AddressInfo, Teacher, Course,Student,TeacherAssisant, GroupConcat


class IndexView(View):
"""主页"""

def get(self, request):
# 查询全部
teachers = Teacher.objects.all()
print(teachers)

# 获取一个值
# 只能返回一条结果,多条会报错
teachers2 = Teacher.objects.get(nickname='Jack')
print(teachers2, type(teachers2))

# 查询符合条件的多个值
# 返回QuerySet,可以是多条结果
teachers3 = Teacher.objects.filter(fans__gte=500)
for teacher in teachers3:
print(f"讲师姓名:{teacher.nickname} --> 粉丝数:{teacher.fans}")

# 字段数据匹配
teacher4 = Teacher.objects.filter(fans__in=[888])
print(teacher4)

# 结果切片
print(Teacher.objects.all()[:2])
# 排序
teacher6 = Teacher.objects.all().order_by('.fans')
for t in teacher6:
print(t.fans)
# 链式查询
teacher7 = Teacher.objects.filter(fans__gte=100).order_by('nickname')
print(teacher7)

# 查询原生SQL
print(Teacher.objects.filter(fans__gte=100).order_by('nickname').query)


# 返回新 Query API
# 排除
print(Student.objects.all().exclude(nickname="王同学"))
# 排序
print(Student.objects.all().exclude(nickname="王同学").reverse())
# 修改返回结果的字段名,将nickname改为name
students = Student.objects.all().extra(select={"name":"nickname"})
for student in students:
print(student.name)

# 获取字典或元组形式的 QuerySet
print(TeacherAssisant.objects.values('nickname', 'hobby'))
# < QuerySet[{'nickname': '助教1', 'hobby': '慕课网学习'}, {'nickname': '助教2', 'hobby': '看电影'}, {'nickname': '助教3', 'hobby': '读书'}] >

print(TeacherAssisant.objects.values_list('nickname', 'hobby'))
# <QuerySet [('助教1', '慕课网学习'), ('助教2', '看电影'), ('助教3', '读书')]>

print(TeacherAssisant.objects.values_list('nickname', flat=True))
# <QuerySet ['助教2', '助教3', '助教1']>

# 根据日期获取查询集
print(Course.objects.dates('created_at', 'day', order='DESC'))
# <QuerySet [datetime.date(2020, 7, 26)]>

print(Course.objects.datetimes('created_at', 'second', order='DESC'))
# <QuerySet [datetime.datetime(2020, 7, 26, 9, 25, 21, tzinfo=<UTC>)]>

# 并集:union、交集:inersection、差集:difference
p_240 = Course.objects.filter(price__gte=240)
p_260 = Course.objects.filter(price__lte=260)
print(p_240.union(p_260))
# 引擎不支持会报错
# print(p_240.inersection(p_260))
# print(p_240.difference(p_260))

# 一对多、多对一查询优化:select_related
# 一对多、多对多查询优化:prefetch_related
courses = Course.objects.all()
for c in courses:
print(f"{c.title} -- {c.teacher.nickname} -- {c.teacher.fans}")
# (0.000) SELECT @@SQL_AUTO_IS_NULL; args=None
# (0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
# (0.000) SELECT `ormbaimoc_course`.`title`, `ormbaimoc_course`.`teacher_id`, `ormbaimoc_course`.`type`, `ormbaimoc_course`.`price`, `ormbaimoc_course`.`volume`, `ormbaimoc_course`.`online`, `ormbaimoc_course`.`created_at`, `ormbaimoc_course`.`updated_at` FROM `ormbaimoc_course`; args=()
# (0.000) SELECT `ormbaimoc_teacher`.`nickname`, `ormbaimoc_teacher`.`introduction`, `ormbaimoc_teacher`.`fans`, `ormbaimoc_teacher`.`created_at`, `ormbaimoc_teacher`.`updated_at` FROM `ormbaimoc_teacher` WHERE `ormbaimoc_teacher`.`nickname` = 'Henry' LIMIT 21; args=('Henry',)
# (0.000) SELECT `ormbaimoc_teacher`.`nickname`, `ormbaimoc_teacher`.`introduction`, `ormbaimoc_teacher`.`fans`, `ormbaimoc_teacher`.`created_at`, `ormbaimoc_teacher`.`updated_at` FROM `ormbaimoc_teacher` WHERE `ormbaimoc_teacher`.`nickname` = 'Henry' LIMIT 21; args=('Henry',)
# (0.000) SELECT `ormbaimoc_teacher`.`nickname`, `ormbaimoc_teacher`.`introduction`, `ormbaimoc_teacher`.`fans`, `ormbaimoc_teacher`.`created_at`, `ormbaimoc_teacher`.`updated_at` FROM `ormbaimoc_teacher` WHERE `ormbaimoc_teacher`.`nickname` = 'Allen' LIMIT 21; args=('Allen',)
# (0.000) SELECT `ormbaimoc_teacher`.`nickname`, `ormbaimoc_teacher`.`introduction`, `ormbaimoc_teacher`.`fans`, `ormbaimoc_teacher`.`created_at`, `ormbaimoc_teacher`.`updated_at` FROM `ormbaimoc_teacher` WHERE `ormbaimoc_teacher`.`nickname` = 'Allen' LIMIT 21; args=('Allen',)
# (0.000) SELECT `ormbaimoc_teacher`.`nickname`, `ormbaimoc_teacher`.`introduction`, `ormbaimoc_teacher`.`fans`, `ormbaimoc_teacher`.`created_at`, `ormbaimoc_teacher`.`updated_at` FROM `ormbaimoc_teacher` WHERE `ormbaimoc_teacher`.`nickname` = 'Allen' LIMIT 21; args=('Allen',)
# (0.000) SELECT `ormbaimoc_teacher`.`nickname`, `ormbaimoc_teacher`.`introduction`, `ormbaimoc_teacher`.`fans`, `ormbaimoc_teacher`.`created_at`, `ormbaimoc_teacher`.`updated_at` FROM `ormbaimoc_teacher` WHERE `ormbaimoc_teacher`.`nickname` = 'Jack' LIMIT 21; args=('Jack',)
# (0.000) SELECT `ormbaimoc_teacher`.`nickname`, `ormbaimoc_teacher`.`introduction`, `ormbaimoc_teacher`.`fans`, `ormbaimoc_teacher`.`created_at`, `ormbaimoc_teacher`.`updated_at` FROM `ormbaimoc_teacher` WHERE `ormbaimoc_teacher`.`nickname` = 'Jack' LIMIT 21; args=('Jack',)
# (0.000) SELECT `ormbaimoc_teacher`.`nickname`, `ormbaimoc_teacher`.`introduction`, `ormbaimoc_teacher`.`fans`, `ormbaimoc_teacher`.`created_at`, `ormbaimoc_teacher`.`updated_at` FROM `ormbaimoc_teacher` WHERE `ormbaimoc_teacher`.`nickname` = 'Jack' LIMIT 21; args=('Jack',)
# (0.000) SELECT `ormbaimoc_teacher`.`nickname`, `ormbaimoc_teacher`.`introduction`, `ormbaimoc_teacher`.`fans`, `ormbaimoc_teacher`.`created_at`, `ormbaimoc_teacher`.`updated_at` FROM `ormbaimoc_teacher` WHERE `ormbaimoc_teacher`.`nickname` = 'Jack' LIMIT 21; args=('Jack',)

courses = Course.objects.all().select_related('teacher')
for c in courses:
print(f"{c.title} -- {c.teacher.nickname} -- {c.teacher.fans}")
# (0.016) (SELECT `ormbaimoc_course`.`title`, `ormbaimoc_course`.`teacher_id`, `ormbaimoc_course`.`type`, `ormbaimoc_course`.`price`, `ormbaimoc_course`.`volume`, `ormbaimoc_course`.`online`, `ormbaimoc_course`.`created_at`, `ormbaimoc_course`.`updated_at` FROM `ormbaimoc_course` WHERE `ormbaimoc_course`.`price` >= 240) UNION (SELECT `ormbaimoc_course`.`title`, `ormbaimoc_course`.`teacher_id`, `ormbaimoc_course`.`type`, `ormbaimoc_course`.`price`, `ormbaimoc_course`.`volume`, `ormbaimoc_course`.`online`, `ormbaimoc_course`.`created_at`, `ormbaimoc_course`.`updated_at` FROM `ormbaimoc_course` WHERE `ormbaimoc_course`.`price` <= 260) LIMIT 21; args=(240, 260)
# (0.000) SELECT `ormbaimoc_course`.`title`, `ormbaimoc_course`.`teacher_id`, `ormbaimoc_course`.`type`, `ormbaimoc_course`.`price`, `ormbaimoc_course`.`volume`, `ormbaimoc_course`.`online`, `ormbaimoc_course`.`created_at`, `ormbaimoc_course`.`updated_at`, `ormbaimoc_teacher`.`nickname`, `ormbaimoc_teacher`.`introduction`, `ormbaimoc_teacher`.`fans`, `ormbaimoc_teacher`.`created_at`, `ormbaimoc_teacher`.`updated_at` FROM `ormbaimoc_course` LEFT OUTER JOIN `ormbaimoc_teacher` ON (`ormbaimoc_course`.`teacher_id` = `ormbaimoc_teacher`.`nickname`); args=()

students = Student.objects.filter(age__lt=30).prefetch_related("course")
for s in students:
print(s.course.all())
# (0.000) SELECT @@SQL_AUTO_IS_NULL; args=None
# (0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
# (0.000) SELECT `ormbaimoc_student`.`nickname`, `ormbaimoc_student`.`age`, `ormbaimoc_student`.`gender`, `ormbaimoc_student`.`study_time`, `ormbaimoc_student`.`created_at`, `ormbaimoc_student`.`updated_at` FROM `ormbaimoc_student` WHERE `ormbaimoc_student`.`age` < 30 ORDER BY `ormbaimoc_student`.`age` ASC; args=(30,)

# 反向查询:父表查询子表
print(Teacher.objects.get(nickname="Jack").course_set.all())
# print(Teacher.objects.get(nickname="Jack").teacher.all())

# annotate(): 使用聚合计数,求和,平均等
print(Course.objects.values('teacher').annotate(vol=Sum('volume')))
print(Course.objects.values('teacher').annotate(vol=Avg('volume')))
print(Course.objects.values('teacher').annotate(vol=Max('volume')))
print(Course.objects.values('teacher').annotate(vol=Min('volume')))

# raw(),执行原始SQL


"""不返回 Query API """
# 获取对象 ---------------------------------
# get()
# get_or_create()
# first()
print(Course.objects.first())

# last()
print(Course.objects.last())

# latest(), 注意需要设置 get_latest_by = 'created_at'
print(Course.objects.latest())

# earliest()
print(Course.objects.earliest())

# in_bulk(), 批量插入数据
print(Course.objects.in_bulk(['Golang 系列教程1', 'Python 系列教程4']))

# 更新对象 ---------------------------------
# update()
Course.objects.filter(title="Golang 系列教程1").update(price=6666)
# update_or_create()
Course.objects.filter(title="Java 系列教程5").update_or_create(title="Java 系列教程5", price=888, volume=55, online=date(2018, 6, 6))

# 删除对象 ----------------------------------
Course.objects.filter(title='Java 系列教程5').delete()

# 其他操作 exists(),count(), aggregate(),判断是否存在,统计个数,聚合
print(Course.objects.filter(title='test').exists())
print(Course.objects.filter(title='Golang 系列教程1').exists())
print(Course.objects.count())
print(Course.objects.aggregate(Max('price'), Min('price'), Avg('price'), Sum(#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author : Baimoc
# @Email : baimoc@163.com
# @Time : 2020/7/26 18:39
# @File : view
from datetime import date

from django.db.models import Sum, Avg, Max, Min
from django.shortcuts import render
from django.views.generic import View
from django.http import JsonResponse
from .models import AddressInfo, Teacher, Course,Student,TeacherAssisant, GroupConcat


class IndexView(View):
"""主页"""

def get(self, request):
# 查询全部
teachers = Teacher.objects.all()
print(teachers)

# 获取一个值
# 只能返回一条结果,多条会报错
teachers2 = Teacher.objects.get(nickname='Jack')
print(teachers2, type(teachers2))

# 查询符合条件的多个值
# 返回QuerySet,可以是多条结果
teachers3 = Teacher.objects.filter(fans__gte=500)
for teacher in teachers3:
print(f"讲师姓名:{teacher.nickname} --> 粉丝数:{teacher.fans}")

# 字段数据匹配
teacher4 = Teacher.objects.filter(fans__in=[888])
print(teacher4)

# 结果切片
print(Teacher.objects.all()[:2])
# 排序
teacher6 = Teacher.objects.all().order_by('.fans')
for t in teacher6:
print(t.fans)
# 链式查询
teacher7 = Teacher.objects.filter(fans__gte=100).order_by('nickname')
print(teacher7)

# 查询原生SQL
print(Teacher.objects.filter(fans__gte=100).order_by('nickname').query)


# 返回新 Query API
# 排除
print(Student.objects.all().exclude(nickname="王同学"))
# 排序
print(Student.objects.all().exclude(nickname="王同学").reverse())
# 修改返回结果的字段名,将nickname改为name
students = Student.objects.all().extra(select={"name":"nickname"})
for student in students:
print(student.name)

# 获取字典或元组形式的 QuerySet
print(TeacherAssisant.objects.values('nickname', 'hobby'))
# < QuerySet[{'nickname': '助教1', 'hobby': '慕课网学习'}, {'nickname': '助教2', 'hobby': '看电影'}, {'nickname': '助教3', 'hobby': '读书'}] >

print(TeacherAssisant.objects.values_list('nickname', 'hobby'))
# <QuerySet [('助教1', '慕课网学习'), ('助教2', '看电影'), ('助教3', '读书')]>

print(TeacherAssisant.objects.values_list('nickname', flat=True))
# <QuerySet ['助教2', '助教3', '助教1']>

# 根据日期获取查询集
print(Course.objects.dates('created_at', 'day', order='DESC'))
# <QuerySet [datetime.date(2020, 7, 26)]>

print(Course.objects.datetimes('created_at', 'second', order='DESC'))
# <QuerySet [datetime.datetime(2020, 7, 26, 9, 25, 21, tzinfo=<UTC>)]>

# 并集:union、交集:inersection、差集:difference
p_240 = Course.objects.filter(price__gte=240)
p_260 = Course.objects.filter(price__lte=260)
print(p_240.union(p_260))
# 引擎不支持会报错
# print(p_240.inersection(p_260))
# print(p_240.difference(p_260))

# 一对多、多对一查询优化:select_related
# 一对多、多对多查询优化:prefetch_related
courses = Course.objects.all()
for c in courses:
print(f"{c.title} -- {c.teacher.nickname} -- {c.teacher.fans}")
# (0.000) SELECT @@SQL_AUTO_IS_NULL; args=None
# (0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
# (0.000) SELECT `ormbaimoc_course`.`title`, `ormbaimoc_course`.`teacher_id`, `ormbaimoc_course`.`type`, `ormbaimoc_course`.`price`, `ormbaimoc_course`.`volume`, `ormbaimoc_course`.`online`, `ormbaimoc_course`.`created_at`, `ormbaimoc_course`.`updated_at` FROM `ormbaimoc_course`; args=()
# (0.000) SELECT `ormbaimoc_teacher`.`nickname`, `ormbaimoc_teacher`.`introduction`, `ormbaimoc_teacher`.`fans`, `ormbaimoc_teacher`.`created_at`, `ormbaimoc_teacher`.`updated_at` FROM `ormbaimoc_teacher` WHERE `ormbaimoc_teacher`.`nickname` = 'Henry' LIMIT 21; args=('Henry',)
# (0.000) SELECT `ormbaimoc_teacher`.`nickname`, `ormbaimoc_teacher`.`introduction`, `ormbaimoc_teacher`.`fans`, `ormbaimoc_teacher`.`created_at`, `ormbaimoc_teacher`.`updated_at` FROM `ormbaimoc_teacher` WHERE `ormbaimoc_teacher`.`nickname` = 'Henry' LIMIT 21; args=('Henry',)
# (0.000) SELECT `ormbaimoc_teacher`.`nickname`, `ormbaimoc_teacher`.`introduction`, `ormbaimoc_teacher`.`fans`, `ormbaimoc_teacher`.`created_at`, `ormbaimoc_teacher`.`updated_at` FROM `ormbaimoc_teacher` WHERE `ormbaimoc_teacher`.`nickname` = 'Allen' LIMIT 21; args=('Allen',)
# (0.000) SELECT `ormbaimoc_teacher`.`nickname`, `ormbaimoc_teacher`.`introduction`, `ormbaimoc_teacher`.`fans`, `ormbaimoc_teacher`.`created_at`, `ormbaimoc_teacher`.`updated_at` FROM `ormbaimoc_teacher` WHERE `ormbaimoc_teacher`.`nickname` = 'Allen' LIMIT 21; args=('Allen',)
# (0.000) SELECT `ormbaimoc_teacher`.`nickname`, `ormbaimoc_teacher`.`introduction`, `ormbaimoc_teacher`.`fans`, `ormbaimoc_teacher`.`created_at`, `ormbaimoc_teacher`.`updated_at` FROM `ormbaimoc_teacher` WHERE `ormbaimoc_teacher`.`nickname` = 'Allen' LIMIT 21; args=('Allen',)
# (0.000) SELECT `ormbaimoc_teacher`.`nickname`, `ormbaimoc_teacher`.`introduction`, `ormbaimoc_teacher`.`fans`, `ormbaimoc_teacher`.`created_at`, `ormbaimoc_teacher`.`updated_at` FROM `ormbaimoc_teacher` WHERE `ormbaimoc_teacher`.`nickname` = 'Jack' LIMIT 21; args=('Jack',)
# (0.000) SELECT `ormbaimoc_teacher`.`nickname`, `ormbaimoc_teacher`.`introduction`, `ormbaimoc_teacher`.`fans`, `ormbaimoc_teacher`.`created_at`, `ormbaimoc_teacher`.`updated_at` FROM `ormbaimoc_teacher` WHERE `ormbaimoc_teacher`.`nickname` = 'Jack' LIMIT 21; args=('Jack',)
# (0.000) SELECT `ormbaimoc_teacher`.`nickname`, `ormbaimoc_teacher`.`introduction`, `ormbaimoc_teacher`.`fans`, `ormbaimoc_teacher`.`created_at`, `ormbaimoc_teacher`.`updated_at` FROM `ormbaimoc_teacher` WHERE `ormbaimoc_teacher`.`nickname` = 'Jack' LIMIT 21; args=('Jack',)
# (0.000) SELECT `ormbaimoc_teacher`.`nickname`, `ormbaimoc_teacher`.`introduction`, `ormbaimoc_teacher`.`fans`, `ormbaimoc_teacher`.`created_at`, `ormbaimoc_teacher`.`updated_at` FROM `ormbaimoc_teacher` WHERE `ormbaimoc_teacher`.`nickname` = 'Jack' LIMIT 21; args=('Jack',)

courses = Course.objects.all().select_related('teacher')
for c in courses:
print(f"{c.title} -- {c.teacher.nickname} -- {c.teacher.fans}")
# (0.016) (SELECT `ormbaimoc_course`.`title`, `ormbaimoc_course`.`teacher_id`, `ormbaimoc_course`.`type`, `ormbaimoc_course`.`price`, `ormbaimoc_course`.`volume`, `ormbaimoc_course`.`online`, `ormbaimoc_course`.`created_at`, `ormbaimoc_course`.`updated_at` FROM `ormbaimoc_course` WHERE `ormbaimoc_course`.`price` >= 240) UNION (SELECT `ormbaimoc_course`.`title`, `ormbaimoc_course`.`teacher_id`, `ormbaimoc_course`.`type`, `ormbaimoc_course`.`price`, `ormbaimoc_course`.`volume`, `ormbaimoc_course`.`online`, `ormbaimoc_course`.`created_at`, `ormbaimoc_course`.`updated_at` FROM `ormbaimoc_course` WHERE `ormbaimoc_course`.`price` <= 260) LIMIT 21; args=(240, 260)
# (0.000) SELECT `ormbaimoc_course`.`title`, `ormbaimoc_course`.`teacher_id`, `ormbaimoc_course`.`type`, `ormbaimoc_course`.`price`, `ormbaimoc_course`.`volume`, `ormbaimoc_course`.`online`, `ormbaimoc_course`.`created_at`, `ormbaimoc_course`.`updated_at`, `ormbaimoc_teacher`.`nickname`, `ormbaimoc_teacher`.`introduction`, `ormbaimoc_teacher`.`fans`, `ormbaimoc_teacher`.`created_at`, `ormbaimoc_teacher`.`updated_at` FROM `ormbaimoc_course` LEFT OUTER JOIN `ormbaimoc_teacher` ON (`ormbaimoc_course`.`teacher_id` = `ormbaimoc_teacher`.`nickname`); args=()

students = Student.objects.filter(age__lt=30).prefetch_related("course")
for s in students:
print(s.course.all())
# (0.000) SELECT @@SQL_AUTO_IS_NULL; args=None
# (0.000) SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; args=None
# (0.000) SELECT `ormbaimoc_student`.`nickname`, `ormbaimoc_student`.`age`, `ormbaimoc_student`.`gender`, `ormbaimoc_student`.`study_time`, `ormbaimoc_student`.`created_at`, `ormbaimoc_student`.`updated_at` FROM `ormbaimoc_student` WHERE `ormbaimoc_student`.`age` < 30 ORDER BY `ormbaimoc_student`.`age` ASC; args=(30,)

# 反向查询:父表查询子表
print(Teacher.objects.get(nickname="Jack").course_set.all())
# print(Teacher.objects.get(nickname="Jack").teacher.all())

# annotate(): 使用聚合计数,求和,平均等
print(Course.objects.values('teacher').annotate(vol=Sum('volume')))
print(Course.objects.values('teacher').annotate(vol=Avg('volume')))
print(Course.objects.values('teacher').annotate(vol=Max('volume')))
print(Course.objects.values('teacher').annotate(vol=Min('volume')))

# raw(),执行原始SQL


"""不返回 Query API """
# 获取对象 ---------------------------------
# get()
# get_or_create()
# first()
print(Course.objects.first())

# last()
print(Course.objects.last())

# latest(), 注意需要设置 get_latest_by = 'created_at'
print(Course.objects.latest())

# earliest()
print(Course.objects.earliest())

# in_bulk(), 批量插入数据
print(Course.objects.in_bulk(['Golang 系列教程1', 'Python 系列教程4']))

# 更新对象 ---------------------------------
# update()
Course.objects.filter(title="Golang 系列教程1").update(price=6666)
# update_or_create()
Course.objects.filter(title="Java 系列教程5").update_or_create(title="Java 系列教程5", price=888, volume=55, online=date(2018, 6, 6))

# 删除对象 ----------------------------------
Course.objects.filter(title='Java 系列教程5').delete()

# 其他操作 exists(),count(), aggregate(),判断是否存在,统计个数,聚合
print(Course.objects.filter(title='test').exists())
print(Course.objects.filter(title='Golang 系列教程1').exists())
print(Course.objects.count())
print(Course.objects.aggregate(Max('price'), Min('price'), Avg('price'), Sum('volume')))

参考

http://www.ruanyifeng.com/blog/2019/02/orm-tutorial.html

https://www.imooc.com/video/18466