#前言:ORM(Object Relational Mapping):对象-关系映射#
1、model与数据库对应关系:
类----------表
属性变量-----表字段
属性对象-----表字段约束
类实例对象---表记录
2、单表基本操作:
DDL就不说了。主要记录下DML语句与orm之间的对比
增加:
sql:INSERT 表名(name,age) VALUES ("john", 23);
orm:类名.objects.create(name="john", age=23)
查询:
sql:SELECT * FROM 表名 where age = 23
orm:类名.objects.filter(age=23)
修改:
sql:UPDATE 表名 SET age = 30 WHERE name = "john"
orm:类名.objects.filter(name="john").update(age=30)
删除:
sql:DELETE FROM 表名 WHERE name = "john"
orm:类名.objects.filter(name="john").delete()
3、model类的常用字段类型:
CharField:字符串字段,用于较短的字符串
IntegerField:整数型
FloatField:浮点型,需指两个参数。max_digits:最大总位数。decimal_places:小数最大位数。
AutoField 通常不使用。如果设置primary_key=True则为自定义主键。
TextField:大容量文本字段
EmailField:带Email合法性校验的CharField,不接受maxlength参数
DateField:日期字段
剩下还有一些不常用给的。CharField大法好。
4、orm常用查询方法:
1、all():查询所有结果
2、filter(**kwargs):查询所有符合筛选条件的对象
3、get(**kwargs):筛选,返回结果有且只有一个,如果筛选的结果超过一个或者没有,则报错
4、exclude(**kwargs):过滤条件取反
5、order_by(*field):排序
6、reverse():反转
7、count:返回查询到的QuerySet对象数量
8、first():返回第一条记录
9、last():返回最后一条记录
10、exists():如果查询到的QuerySet包含数据就返回True,否则返回False。
11、distinct():返回结果去重
12、values(*field):返回一个ValueQuerySet。
5、基于双下划线的模糊查询:
类名.objects.filter(price__in=[100,200,300]) # price字段值是否为其中选项之一
类名.objects.filter(price__gt=[100]) # price字段值是否大于选项
类名.objects.filter(price__lt=[100]) # price字段值是否小于选项
类名.objects.filter(price__range=[100,200]) # price字段值是否位于选项区间之内
类名.objects.filter(title__contains=["john"]) # title字段值是否包含该字符串,区分大小写
类名.objects.filter(title__icontains=["John"]) # title字段值是否包含该字符串,不区分大小写
类名.objects.filter(title__startswith=["py"]) # title字段值是否以该字符串开头
6、多表操作(ForeignKey和ManyToManyField):
1、一对多ForeignKey操作
1、添加记录:
orm:类名.objects.create(name="john", age=23,关联表字段=xx) # 与单表一样,就是多一个字段
2、多对多ManyToManyField
假设a表与b表多对多,生成了第三张关系表c
1、添加记录:
result = a.objects.get(id=1)
result.b.add(2)
c表添加一条关联记录。a表id=1,b表id=2
2、删除记录:
方式1:
result = a.objects.get(id=1)
result.b.remove(2,3)
c表删除两条关联记录。a表id=1,b表id=2或者b表id=3
方式2:
result = a.objects.get(id=1)
result.b.clear()
c表所有关于a.id=1的记录全部删除
方式3:
result = a.objects.get(id=1)
result.b.set(4)
c表删除所有a.id=1的记录。然后插入一条记录a.id=1,b.id=4
3、中介模型:
a表与b表。在a表中设置ManyToManyField生成c表的时候,c表默认仅有两个表
的关联字段,且无法修改。但是在绑定ManyToManyField的时候添加through=“xxx”
后,则可以进行自定义第三张xxx关联表,随意编辑,django不会自动创建。
4、跨表查询:
假设现在有a、b、c、三个表。a跟b一对多,a表设置ForeignKey,a表和c表多对多。
a表设置ManyToManyField
####基于对象(子查询)
正向查询按字段,反向查询按relate_name,如果没有设置。按照表名小写_set
a查b -- 正查:
result = A.object.get(id=1)
result.b.all() #因为这里b是多的一方,所以要加all。如果查的是1的一方,则不加。
b查a -- 反查:
result = B.object.get(id=1)
result.a_set
ManyToManyField和OneToOneField同理。
####基于双下划线(join查询)
正向查询按字段,反向查询按表名小写
根据a表id字段查b表的name字段
A.objects.filter(id=1).values("b__name") 正向查询
b.object.filter(a_id=1).values("name") 反向查询
* filter这里也可以结合模糊搜索查询。
5、分组查询
聚合
A.objects.all().aggregate(AVG("xxxx"))
分组
单表分组:A表有dep字段。按照dep字段分组。求平均薪水
sql:select dep,AVG(salary) form A group by dep
orm: A.objects.values("dep").annotate(avg=AVG("salary")) #annotate前面的是分组字段
所以一般不用all用value。
跨表分组:
方式1:A.objects.value(id).annotate(c=Count("b")) #根据a表主键分组,count b表主键 返回id和c两个字段
方式2:A.objects.all.annotate(c=Count("b")).values("c","xxx")
方式2可以指定返回数据,更加实用
总结:
一个复杂的ORM具体样式如下:如用户表和订单表。查询所有姓刘的用户的个人最高单价订单。返回用户姓名和订单中最高的金额, 假设user表id与order表cus_id关联
SELECT a.username, max( b.prcie ) FROM USER AS a INNER JOIN ORDER AS b WHERE a.id = b.cus_id AND username LIKE "刘%" GROUP BY cus_id
转换成orm就应该如下:
User.object.filter(username__startswith="刘").annotate(max_price=Max("order__price")).values("username","max_price")
ps:1、在模型类中关联字段设置db_constraint=False,可使约束仅限于orm而不影响到到数据库
2、频繁使用多对多会生成大量的关联表。不利于维护。提前构思好结构。