概述:Django对各种数据库都提供了很好的支持,Django为这些数据库提供了统一的调用接口API,程序员可以根据自己的业务需求选择不同的数据库
ORM简介
概述:对象-关系-映射
作用: 根据类生成表结构;将对象、列表的操作转换成对应的SQL语句;将SQL语句查询到的结果转换为对象或者列表
优点:极大的减轻开发人员的工作量,不需要面对因数据库的变更而导致代码无效在修改代码
图解:
定义模型
模型、属性、表、字段之间的关系:一个模型在数据库中对应一张表,在模型中定义的属性对应该模型对照表中的一个字段
创建模型类
班级类
class Grade(models.Model):
name = models.CharField(max_length=20)
boyNum = models.IntegerField()
girlNum = models.IntegerField()
isDelete = models.BooleanField(default=False)
def __str__(self):
return self.name
学生类
class Student(models.Model):
name = models.CharField(max_length=20)
sex = models.BooleanField()
age = models.IntegerField()
contend = models.CharField(max_length=40)
# 关联类名的小写或直接类名 Grade
grade = models.ForeignKey("grade")
isDelete = models.BooleanField(default=False)
def __str__(self):
return self.name
元选项
在模型类中定义一个Meta类,用于设置元信息
class Student(models.Model):
name = models.CharField(max_length=20)
sex = models.BooleanField()
age = models.IntegerField()
contend = models.CharField(max_length=40)
# 关联类名的小写
grade = models.ForeignKey("grade")
isDelete = models.BooleanField(default=False)
def __str__(self):
return self.name
class Meta():
db_table = "students"
ordering = ["-id"]
属性
- db_table: 定义数据表名,推荐使用类名小写,并且添加复数
- ordering: 规定对象的默认排序字段 ; ordering = ["id"]: 正序; ordering = ["-id"]: 倒序;
注意:排序会增加数据库的开销
模型成员
objects对象
概述: 是Manager类型的对象,用于与数据库进行交互; 当定义模型时没有指定管理器,则Django会为模型提供一个名为objects的管理器
自定义模型管理器
class Student(models.Model):
#自定义模型管理器
myobject = models.Manager()
name = models.CharField(max_length=20)
sex = models.BooleanField()
age = models.IntegerField()
contend = models.CharField(max_length=40)
# 关联类名的小写
grade = models.ForeignKey("grade")
isDelete = models.BooleanField(default=False)
def __str__(self):
return self.name
class Meta():
db_table = "students"
ordering = ["-id"]
注意: 如果为模型指定了管理器,那么Django不再为模型类提供名为objects的管理器
自定义模型管理器类
class StudentManager(models.Manager):
def get_queryset(self):
return super(StudentManager, self).get_queryset().filter(isDelete=False)
class Student(models.Model):
#自定义模型管理器
objects = StudentManager()
get_queryset获取查询集(数据集),自定义管理器类调用父类中的get_queryset方法后在进行过滤
增
创建对象
当创建对象时,Django不会对数据库进行读写操作。调用save()方法才与数据库进行交互,将对象存储到数据库中。__init__方法已经在基类models.Model中使用,在自定义模型类中无法使用
在模型类中增加一个类方法:
class Student(models.Model):
#自定义模型管理器
objects = StudentManager()
name = models.CharField(max_length=20)
sex = models.BooleanField()
age = models.IntegerField()
contend = models.CharField(max_length=40)
# 关联类名的小写
grade = models.ForeignKey("grade")
isDelete = models.BooleanField(default=False)
def __str__(self):
return self.name
class Meta():
db_table = "students"
ordering = ["-id"]
@classmethod
def create(cls, name, sex, age, contend, grade):
return cls(name=name, sex=sex, age=age, contend=contend, grade=grade)
在自定义模型器类中增加一个方法
class StudentManager(models.Manager):
def get_queryset(self):
return super(StudentManager, self).get_queryset().filter(isDelete=False)
def create(self, name, sex, age, contend, grade):
obj = self.model()
obj.name = name
obj.sex = sex
obj.age = age
obj.contend = contend
obj.grade = grade
return obj
查询
简介
查询集:表示从数据库中获取的对象集合,查询集可以含有一个或者多个过滤器
过滤器:基于所给的参数限制查询集的结果,得到新的查询集
从SQL的角度,查询集合select语句等价,过滤器就像where和limit子句相似
查询集
在管理器上调用过滤器方法或者是其他数据查询集上调用过滤器方法得到新的查询集
查询集经过过滤器筛选得到新的查询集,因此可以使用链式语法结构
惰性查询:创建查询集不会带来任何的数据库访问,直到调用数据时,才会访问数据库
什么时候对查询集求值? 迭代、序列化、与if合用
返回查询集的方法
all()
返回查询集的方法
def students(request):
stus = Student.objects.all()
return render(request, 'students.html', {"stus":stus})
filter()
作用:将符合条件的数据过滤进来
使用:filter(键1=值1, 键2=值2);filter(键1=值1, 键2=值2)
def students(request):
stus = Student.objects.filter(age=20)
return render(request, 'students.html', {"stus":stus})
exclude()
作用: 将符合条件的数据过滤出去
def students(request):
stus = Student.objects.exclude(age=20)
return render(request, 'students.html', {"stus":stus})
order_by()
作用:排序
def students(request):
stus = Student.objects.order_by("age")
return render(request, 'students.html', {"stus":stus})
def students(request):
stus = Student.objects.order_by("-age")
return render(request, 'students.html', {"stus":stus})
values()
作用: 一个对象构成一个字典,然后构成一个列表返回
def students(request):
stus = Student.objects.values()
print(stus)
return render(request, 'students.html', {"stus":stus})
返回单个值的方法
get()
作用: 返回单个满足条件的对象
def students(request):
# pk代表主键
try:
stus = [Student.objects.get(age=20)]
except Student.DoesNotExist as e:
pass
except Student.MultipleObjectsReturned as e:
pass
return render(request, 'students.html', {"stus":stus})
注意: 如果多条数据被返回,会引发 “类名.MultipleObjectsReturned” 异常;数据不存在会报 "类名.DoesNotExist" 异常
count()
返回当前查询的总条数
first()
返回查询集中的第一个对象
last()
返回查询集中的最后一个对象
exists()
判断查询集中是否有数据,如果有返回True,否则返回False
def students(request):
stus = Student.objects.filter(age=20)
if stus.exists():
return render(request, 'students.html', {"stus":stus})
else:
return HttpResponse("没有学生数据")
限制查询集
查询集返回列表,可以使用下标的方式进行限制,等同于SQL中的limit和offset子句
注意: 不支持负数索引; 使用下标后返回一个新的查询集,不会立即执行查询
def students(request):
stus = Student.objects.all()[5:10]#[0:5)
return render(request, 'students.html', {"stus":stus})
字段查询
概述
实现where子句,作为filter()、exclude()、get()的参数
语法 : 属性名称__比较运算符=值 (注意:里面有两个下划线)
外键: 使用 “属性名_id” 表示原始的外键值
转义: like语句中使用%,可以直接使用
比较运算符
exact: 表示判断相当,大小写敏感
contains: 是否包含,大小写敏感
# 找描述中带有"sunck"的所有学生
def students(request):
stus = Student.objects.filter(contend__icontains="sunck")
return render(request, 'students.html', {"stus":stus})
startswith、endswith: 以value开头、结尾,大小写敏感
# 找描述以sunck开头的所有学生
def students(request):
stus = Student.objects.filter(contend__startswith="sunck")
return render(request, 'students.html', {"stus":stus})
iexact、icontains、istartswith、iendswith: 不区分大小写
isnull, isnotnull : 是否为空, 是否为非空
in : 包含在范围之内
# 找id为2,5,8,9的学生
def students(request):
stus = Student.objects.filter(pk__in=[2,5,8,9])
return render(request, 'students.html', {"stus":stus})
gt, gte, lt, lte
# 找年龄大于等于20的所有学生
def students(request):
stus = Student.objects.filter(age__gte=20)
return render(request, 'students.html', {"stus":stus})
year、month、day、week_day、hour、minute、second: 对日期类型的属性进行运算
跨关联关系的查询
处理join查询:
语法:关联的模型类名小写__属性名__比较运算符=值
注意: __比较运算符 没有,表示等于; 可以反向使用,即关联的两个模型中都可以使用
# 描述中带有sunck的学生属于那些班级
def students(request):
grades = Grade.objects.filter(student__contend__contains="sunck")
print(grades)
stus = Student.objects.all()
return render(request, 'students.html', {"stus":stus})
查询的快捷方式: pk pk表示主键,默认主键是id
聚合函数
注意: 使用aggregate()函数返回聚合函数的值
函数: Avg、Count、Max、Min、Sum
# 求所有人的年龄的和
from django.db.models import Sum
def students(request):
age = Student.objects.aggregate(Sum("age"))
print("***********", age)
stus = Student.objects.all()
return render(request, 'students.html', {"stus":stus})
F对象
作用: 可以使模型中的A字段与B字段进行比较,如果A字段出现在等号的左侧,那么B字段使用F对象写在等号右侧
# 找男生个数多于女生个数的班级
from django.db.models import F
def students(request):
grades = Grade.objects.filter(boyNum__gt=F("girlNum"))
print(grades)
stus = Student.objects.all()
return render(request, 'students.html', {"stus":stus})
F对象可以进行数学运算
from django.db.models import F
def students(request):
grades = Grade.objects.filter(boyNum__gt=F("girlNum")*2)
print(grades)
stus = Student.objects.all()
return render(request, 'students.html', {"stus":stus})
F对象还可以进行关联查询 模型类小写__属性名
# 没有被删除的学生的班级
from django.db.models import F
def students(request):
grades = Grade.objects.filter(isDelete=F("student__isDelete"))
print(grades)
stus = Student.objects.all()
return render(request, 'students.html', {"stus":stus})
对于data/time字段,可以进行timedelta()进行运算
Q对象
逻辑与
# 年龄大于等于20且小于等于50的学生
def students(request):
stus = Student.objects.filter(age__gte=20,age__lte=50)
return render(request, 'students.html', {"stus":stus})
def students(request):
stus = Student.objects.filter(age__gte=20).filter(age__lte=50)
return render(request, 'students.html', {"stus":stus})
from django.db.models import Q
def students(request):
stus = Student.objects.filter(Q(age__gte=20) & Q(age__lte=50))
return render(request, 'students.html', {"stus":stus})
逻辑或
# 获取年龄小于20或者年龄大于50的学生
from django.db.models import Q
def students(request):
stus = Student.objects.filter(Q(age__lt=20) | Q(age__gt=50))
return render(request, 'students.html', {"stus":stus})
逻辑非
# 获取年龄不大于等于20的学生
def students(request):
stus = Student.objects.filter(age__lt=20)
return render(request, 'students.html', {"stus":stus})
from django.db.models import Q
def students(request):
stus = Student.objects.filter(~Q(age__gte=20))
return render(request, 'students.html', {"stus":stus})
注意: 过滤器函数中可以混合使用Q对象和关键字参数,所有参数条件都将and在一起,Q对象必须位于关键字参数的前面
模型关系
1-1
使用场景: 表的字段太多,需要拆分
# 人
class Person(models.Model):
name = models.CharField(max_length=20)
age = models.IntegerField()
# 关系存放在哪张表都可以
# 绑定身份证与人的一对一关系,默认情况下当删身份证时绑定的人也可以删除,通过on_delete属性设置
idCard = models.OneToOneField(IDCard)
# 身份证
class IDCard(models.Model):
sex = models.BooleanField()
num = models.CharField(max_length=20)
主从从表: 声明关系的表为从表
级联数据获取:
从获取主:
- 关系是直接声明的,是一个显性的属性
- 获取pk为1的人的身份证号
- per = Person.objects.get(pk=1) print(per.idCard.num)
主获取从:
- 关系字段是隐性属性,对象.关系模型类名的小写
- 获取身份证号是1的人的姓名
- card = IDCard.objects.get(pk=1) print(card.person.name)
删除数据
1-n
主表从表: 声明关系的表为从表
级联数据获取:
- 从获取主: 关系是直接声明的,是一个显性的属性
- 主获取从: 关系字段是隐性属性,对象.模型类小写_set
#找到1班的所有学生
grade = Grade.objects.get(pk=1)
print(grade.student_set.all())
m-n
原理: 底层是通过两个外键实现,两个外键存在于另一张关系表中
#多对多
class Buyer(models.Model):
name = models.CharField(max_length=20)
level = models.IntegerField()
class Product(models.Model):
name = models.CharField(max_length=20)
price = models.IntegerField()
#关系形成
buyers = models.ManyToManyField(Buyer)
形成关系
def ptob(reqeust, p, b):
product = Product.objects.get(pk=p)
buyer = Buyer.objects.get(pk=b)
#产生关联
product.buyers.add(buyer)
return HttpResponse("购买成功")
数据级联获取
从获取主
- 对象.显性属性,得到的是一个数据集合,可以进行过滤
- 已知一件商品,获取该商品所有的购买者
- product = Product.objects.get(pk=1) print(product.buyers.all())
主获取从:
- 隐性属性 对象.关联类名小写_set 得到的是一个数据集合,可以进行过滤
- 已知一个购买者,获取他所买的所有商品
- buyer = Buyer.objects.get(pk=1) print(buyer.product_set.all())
模型继承
使用最原始的python类的继承方式
class Animal(models.Model):
name = models.CharField(max_length=20)
age = models.IntegerField()
class Cat(Animal):
weight = models.IntegerField()
class Dog(Animal):
height = models.IntegerField()
注意: 默认继承方式不是很合理
- 父类也会对应一张表
- 默认在父类中定义的字段会存在父类表中,子类的数据通过外键关联父表中数据,子类只有特殊的数据在子表中
- 效率比较低
Django中的数据库模块提供了一个非常不错的功能,就是支持models的面向对象,可以在Meta类中指定是否抽象,然后继承
class Animal(models.Model):
name = models.CharField(max_length=20)
age = models.IntegerField()
class Meta():
# 让该类抽象,抽象的父类不会再生产数据表
# 子类会继承父类中的通用数据,复制到子表中
abstract = True
class Cat(Animal):
weight = models.IntegerField()
class Dog(Animal):
height = models.IntegerField()
数据库的优化策略
避免IO 避免关系过多级联
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。