django 表操作(增删改查)
一:查看orm写的sq语句
如果对某个语句不清楚的话可以调用queryset的的query方法来查看sql。
1 obj=Hostinfo.objects.filter(id=val).values(id)
2 print(obj.query)
一:基本操作
包括增删改查
1 # 增 2 # 3 # models.Tb1.objects.create(c1='xx', c2='oo') 增加一条数据,可以接受字典类型数据 **kwargs 4 5 # obj = models.Tb1(c1='xx', c2='oo') 6 # obj.save() 7 8 # 查 9 # 10 # models.Tb1.objects.get(id=123) # 获取单条数据,不存在则报错(不建议) 11 # models.Tb1.objects.all() # 获取全部 12 # models.Tb1.objects.filter(name='seven') # 获取指定条件的数据 13 14 # 删 15 # 16 # models.Tb1.objects.filter(name='seven').delete() # 删除指定条件的数据 17 18 # 改 19 # models.Tb1.objects.filter(name='seven').update(gender='0') # 将指定条件的数据更新,均支持 **kwargs 20 # obj = models.Tb1.objects.get(id=1) 21 # obj.c1 = '111' 22 # obj.save() # 修改单条数据
其中需要注意的是:django中的and用法:是用逗号, 比如说:models.Tb1.objects.filter(name='seven' ,id=2).delete()表示的是删除name='seven' 并且id=2.
这里的filter相当于where条件。
查询:
通常我们查询的出的语句是一个对象的列表,列表内的对象并不是python 的对象,是django的类的一个对象。queryset对象。
比如:
1 def test(request): 2 user_obj=models.Title.objects.filter(title='evil') 3 print(type(user_obj)) 4 return HttpResponse('ok') 5 <class 'django.db.models.query.QuerySet'>
modle的表的类的对象是数据库中的列的对象。
如果我们查询的时候不想要对象的列表,那我们使用values和value_list的参数进行查找。获取是不是对象,而是特殊的列表!
values:
1 def test(request): 2 user_obj=models.Title.objects.filter(title='evil').values('title') 3 print(user_obj) 4 return HttpResponse('ok') 5 <QuerySet [{'title': 'evil'}, {'title': 'evil'}, {'title': 'evil'}]>#可以看做列表中嵌套字典形式。
可以进行循环输出:
1 def test(request): 2 user_obj=models.Title.objects.filter(title='evil').values('title') 3 print(user_obj) 4 for item in user_obj: 5 print(item['title']) 6 return HttpResponse('ok') 7 <QuerySet [{'title': 'evil'}, {'title': 'evil'}, {'title': 'evil'}]> 8 evil 9 evil 10 evil
values_list来查询的时候,数组的集合。也就是列表中嵌套元组形式!!可以获取多个字段!!
1 def test(request): 2 user_obj=models.Title.objects.filter(title='evil').values_list('title') 3 print(user_obj) 4 for item in user_obj: 5 print(item) 6 return HttpResponse('ok') 7 <QuerySet [('evil',), ('evil',), ('evil',)]> 8 ('evil',) 9 ('evil',) 10 ('evil',
二:进阶操作 了不起的双下划线 __
1 # 获取个数 2 # 3 # models.Tb1.objects.filter(name='seven').count() 4 5 # 大于,小于 6 # 7 # models.Tb1.objects.filter(id__gt=1) # 获取id大于1的值 8 # models.Tb1.objects.filter(id__lt=10) # 获取id小于10的值 9 # models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值 10 11 # in 12 # 13 # models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据 14 # models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in 15 16 # contains 17 # 18 # models.Tb1.objects.filter(name__contains="ven") 19 # models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感 20 # models.Tb1.objects.exclude(name__icontains="ven") 21 22 # range 23 # 24 # models.Tb1.objects.filter(id__range=[1, 2]) # 范围bettwen and 25 26 # 其他类似 27 # 28 # startswith,istartswith, endswith, iendswith, 29 30 # order by 31 # 32 # models.Tb1.objects.filter(name='seven').order_by('id') # asc 33 # models.Tb1.objects.filter(name='seven').order_by('-id') # desc 倒序排列。 34 35 # limit 、offset 36 # 37 # models.Tb1.objects.all()[10:20]##这个limit 不是去数据库取所有的数据。 38 39 # group by 40 from django.db.models import Count, Min, Max, Sum 41 # models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num')) 42 # SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"
需要注意的是:models.Tb1.objects.all()[10:20] 不是取所有的数据而是limit获取指定的列。。。。
1 models.Tb1.objects.filter(name='seven').order_by('id') # asc 2 models.Tb1.objects.filter(name='seven').order_by('-id') # desc 倒序排列。
需要注意的是:当参数前面加负号(-)的时候,表示的是倒序。!!!
了不起的双下划线:
一对多
增加: 没有外键的表。插入数据没有限制。而有外键的表,需要依赖另一个张表,在django中,含有外键的表的列,是另一个表的对象。有如下数据的插入,有如下的方法:
1、直接插入对象,但是这种方法有个弊端,需要多次的查询库。效率不高。
表结构:
1 from django.db import models 2 3 # Create your models here. 4 class UserType(models.Model): 5 name=models.CharField(max_length=32) 6 7 class User(models.Model): 8 username=models.CharField(max_length=32) 9 pwd=models.CharField(max_length=32) 10 user_type=models.ForeignKey('UserType')
插入语句:
1 def test(request): 2 # models.UserType.objects.create(name='管理员') 3 models.User.objects.create(username='evil',pwd='123',user_type=models.UserType.objects.filter(id=1).first()) 4 return HttpResponse('ok')
需要查询2次库。效率不高,需要注意的插入的是对象,不是列表。需要加first()
2:直接插入,在django 中 含有外键的列,在实际数据库中是:列名_id
含有外键的表结构:
这个id的值和关联的表的id值是一致的。
插入语句:
表结构:
1 from django.db import models 2 3 # Create your models here. 4 class UserType(models.Model): 5 name=models.CharField(max_length=32) 6 7 class User(models.Model): 8 username=models.CharField(max_length=32) 9 pwd=models.CharField(max_length=32) 10 user_type=models.ForeignKey('UserType')
1 from django.shortcuts import render,HttpResponse 2 from test_mo import models 3 # Create your views here. 4 def test(request): 5 # models.UserType.objects.create(name='管理员') 6 models.User.objects.create(username='tom',pwd='123',user_type_id=2) 7 return HttpResponse('ok')
查询:对于一对多,跨表查询,比如上面的表结构:
1 from django.db import models 2 3 # Create your models here. 4 class UserType(models.Model): 5 name=models.CharField(max_length=32) 6 7 class User(models.Model): 8 username=models.CharField(max_length=32) 9 pwd=models.CharField(max_length=32) 10 user_type=models.ForeignKey('UserType')
我现在想查询:用户类型为管理员的用户名和密码。
分析:常规的是:先查询UserType 这表的类型为“”管理员”的id,然后在查询User表中user_type_id=2的用户名。
这样查询:对数据库进行了2次查询。比较繁琐,通过双下划线可以进行简单的查询.
1 from django.shortcuts import render,HttpResponse 2 from test_mo import models 3 # Create your views here. 4 def test(request): 5 queyry_res=models.User.objects.filter(user_type__name='管理员').values_list('username','pwd') 6 print(queyry_res) 7 return HttpResponse('ok') 8 <QuerySet [('tom', '123')]>#返回一个特殊的列表含有元组的。
通过含有外键的(列__name='xx')来筛选我们想要的数据。
虽然我们在执行多对一的查询的时候,都是正向查询。其实django 在多对一的情况下给咱们提供和多对多的反向查询提供的虚拟列 是一样都是:tablename_set(tablename为含有foreign key的表)来反向查询:
modles:
1 class Person(models.Model):
2 name=models.CharField(max_length=32)
3
4 class Favor(models.Model):
5 fav_name=models.CharField(max_length=32)
6 p_fav=models.ForeignKey('Person')
需求:名字叫做evil的爱好是什么?进行反向查询:
1 def person(request):
2 per_obj=models.Person.objects.filter(name='evil').first()
3 print(per_obj.favor_set.all().first().fav_name)
4 return HttpResponse('ok')
注意:person是对多个favor 所以的查询的结果是集合。
同样favor_set 和多对多一样也有add 方法等。
虽然Person有这些方法,但是Favor没有这些方法(add、all等)!!!注意和多对多的区别!
注意:双下划线是参数!!django 只是通过双下划线来查找另一个张表。而在表结构中,外键列是他关联的表的对象可以直接通过点.属性获取!!!而不是双下划线!!!
1 def test(request): 2 queyry_res=models.User.objects.filter(user_type__name='管理员') 3 print(queyry_res) 4 print(queyry_res[0].user_type.name) 5 return HttpResponse('ok') 6 <QuerySet [<User: User object>]> 7 管理员
即查询的结果。不能通过双下划线来获取字段,而是通过点.属性来获取。
对于values和values_list 可以进行跨表的查询。语法如下:
1 from django.shortcuts import render,HttpResponse 2 from test_mo import models 3 # Create your views here. 4 def test(request): 5 query_res=models.User.objects.filter(id=2).values_list('user_type__name') 6 print(query_res) 7 return HttpResponse('ok') 8 <QuerySet [('管理员',)]>
双下划线可以跨一张、多张表进行查询。。。。
有如下表结构:
1 from django.db import models 2 3 # Create your models here. 4 class UserType(models.Model): 5 name=models.CharField(max_length=32) 6 gender=models.ForeignKey('Gender') 7 8 class User(models.Model): 9 username=models.CharField(max_length=32) 10 pwd=models.CharField(max_length=32) 11 user_type=models.ForeignKey('UserType',default=1) 12 13 14 class Gender(models.Model): 15 gender=models.CharField(max_length=32)
需求:查看用户的名为tom的对应的性别。
方法1:
1 def test(request): 2 res=models.User.objects.filter(username='tom').values_list('user_type__gender__gender') 3 print(res) 4 return HttpResponse('ok') 5 <QuerySet [('男',)]>
通过2个双下划线查找到第三张表的内的属性值。
方法2:因为双下划线是只是参数。因为外键对应的列是关联的表的对象实例。我们可以通过这个对象实现关联到另一个对象的实例以此类推。。。。来查找多个表的字段。
1 def test(request): 2 res=models.User.objects.filter(username='tom') 3 for item in res: 4 print(item.user_type.gender.gender) 5 # models.UserType.objects.create(name='游客',gender_id=1) 6 # models.Gender.objects.create(gender="女") 7 return HttpResponse('ok') 8 男 9 男
modle 类中外键对应列 实际上数据库中储存对应的列为:列名_id 比如上面user_type_id、gender_id。
插入数据的时候,在数据库层面上可以直接指定user_type_id=xxx,gender_id=xxx。
在modle类中,我们需要创建对应的外键的 user_type的对象、gender对象来插入。
查询的时候,需要借助django的双下划线参数或者根据插入的外键的时候是另一张表的对象,通过点.来获取我们想要的字段。
一个数据库的实际存储的情况。
一个django 给咱们提供相应的方法。查询的时候需要根据django提供的方法。而不是通过实际数据库存储的情况。当然也可以根据数据库实际存储情况来写原生的sql。
多对多表结构
多对多关系,通过第三张表来建立关系,之前的博客中已经介绍了多对多的情况。如果我们不手动创建第三张表的话,默认django会自动创建第三张。如果我们手动创建的第三张表的话,用foreign key来建立关系。
1:django方式:从django的本质
code:
1 class Gender(models.Model): 2 gender=models.CharField(max_length=32) 3 4 5 6 class Boy(models.Model): 7 boyname=models.CharField(max_length=32) 8 9 class Gril(models.Model): 10 gril_name=models.CharField(max_length=32) 11 btog=models.ManyToManyField('Boy')
执行:python manager.py makemigrations python manager.py migrate
我们查看下数据库中表的变化。我们可以看到除了boy和girl 表之外,django 为我们创建第三张表:gril_btog表。 表名是我们创建ManyToMany字段的和当前表的组合。表字段是:gril_id 和boy_id。
2:创建外键方式:
code:
1 class Man(models.Model): 2 man_name=models.CharField(max_length=32) 3 4 class Woman(models.Model): 5 woman_name=models.CharField(max_length=32) 6 7 class MantoWoman(models.Model): 8 to_man=models.ForeignKey('Man') 9 to_woman=models.ForeignKey('Woman')
上面是我们建立多对多关系的表结构。无论哪一种,都是通过第三张表建立关系。第三张表储存的数据结构都是对应的id,这和sqlalchemy是一样的。
那着重介绍第一种方法的查询:
django 为我们建立第三张表。我们建表的代码如下:
1 class Boy(models.Model): 2 boyname=models.CharField(max_length=32) 3 4 class Gril(models.Model): 5 gril_name=models.CharField(max_length=32) 6 btog=models.ManyToManyField('Boy')
2张表中唯一和第三张有关系的只有:Gril表的btog字段有关。那我们先给这2个张表的插入数据。
插入数据代码:
1 def boy(request): 2 boy_1=request.GET.get('v1',None) 3 if boy_1: 4 models.Boy.objects.create(boyname=boy_1) 5 return HttpResponse(boy_1) 6 def gril(request): 7 gril_1=request.GET.get('v1',None) 8 if gril_1: 9 models.Gril.objects.create(gril_name=gril_1) 10 return HttpResponse(gril_1)
通过get传入参数插入值:http://127.0.0.1:8000/gril/?v1=luc2
数据库:
由于第三张表没有插入值。boy表和gril表没有关系。
正向操作:
我们把通过含有ManyToMany的字段的表来操作第三张表我们叫做正向操作.
唯一有关系的是gril表中btog字段。
插入单行数据:
我们可以通过这个字段来给第三张表插入值。注意get查看获取的是单个queryset对象不是列表。
代码:
1 def boytogril(request): 2 girl_obj=models.Gril.objects.get(id=1) 3 print(girl_obj.gril_name) 4 boy_obj=models.Boy.objects.get(id=1) 5 girl_obj.btog.add(boy_obj) 6 return HttpResponse('ok')
第三张表:
如上的girl_obj.btog 字段通过add()方法给第三张表插入数值。该字段有数据相关的操作(增删改查)所有方法。
我们可以通过all方法来查看第三张表。
1 def boytogril(request): 2 girl_obj=models.Gril.objects.get(id=1) 3 print(girl_obj.gril_name) 4 boy_obj=models.Boy.objects.get(id=1) 5 print(girl_obj.btog.all()) 6 return HttpResponse('ok')
插入多行数据:
我们可以通过add()方法传入一个列表,来让girl表和boy表产生关系。而不是用多次或者for循环来添加 我们想要关联的数据。
code:
1 def boytogril(request): 2 girl_obj=models.Gril.objects.get(id=2) 3 print(girl_obj.gril_name) 4 boy_list=models.Boy.objects.all() 5 girl_obj.btog.add(*boy_list) 6 print(girl_obj.btog.all()) 7 return HttpResponse('ok')
让id=2的女孩和所有的男孩产生一对多的关系。注意的是当我们传入的列表的时候,add()方法,参数需要加*
结果:
1 luc2 2 <QuerySet [<Boy: Boy object>, <Boy: Boy object>, <Boy: Boy object>, <Boy: Boy object>]>
第三张表:
我们也可以按照我们的筛选的条件进行数据的插入:
1 def boytogril(request): 2 girl_obj=models.Gril.objects.get(id=3) 3 print(girl_obj.gril_name) 4 boy_list=models.Boy.objects.filter(id__in=[2,4]) 5 girl_obj.btog.add(*boy_list) 6 print(girl_obj.btog.all()) 7 return HttpResponse('ok')
我们让id=3的lili 和 id为2 和4的男孩产生关系。注意双下划线条件的筛选!!
1 lili 2 <QuerySet [<Boy: Boy object>, <Boy: Boy object>]>
第三张表:
根据ID 插入数值:
从数据库本质:
我们观察到实际上第三张表插入的数值是数字。我们可以给add()方法传入数字进行插入。
和多对一不同的是:是在外键列对应数据库里是当前列名_id的字段列。我们可以直接给这个列赋值进行插入也外键列赋值关联表的对象。
code:
1 def boytogril(request): 2 girl_obj=models.Gril.objects.get(id=4) 3 print(girl_obj.gril_name) 4 # boy_list=models.Boy.objects.filter(id__in=[2,4]) 5 girl_obj.btog.add(*[1,3]) 6 print(girl_obj.btog.all()) 7 return HttpResponse('ok')
1 女帝 2 <QuerySet [<Boy: Boy object>, <Boy: Boy object>]>
第三张表:
我们给id为4的女帝和id为1、3的男孩产生关系。我们直接给add出入id的数字既可。
反向操作
通过不含有ManyToMany的字段的表操作第三张表,我们叫做反向操作。
在django层面上,在不含有ManyToMany的字段的表,里隐式的给我们创建一列。这是一个虚拟的列,实际数据库中不存在,他的作用是让我们操作数据库更为方便。
这个列是以含有ManyToMany的字段的表名加上下划线和set组合成列名:tablename_set。
我们可以通过这个字段来操作第三张表。这个操作叫做反向操作。
数据的插入:
1 def boytogril(request): 2 boy_obj=models.Boy.objects.filter(id=5).first() 3 print(boy_obj.boyname) 4 boy_obj.gril_set.add(*[1,2]) 5 return HttpResponse('ok') 6 jack
给id=5的jack和id为1或者2的女孩产生关系。默认在django给咱们创建虚拟列:gril_set列。我们可以通过这个列给操作第三张表。
第三张表:
当然也可以插入对象。
1 def boytogril(request): 2 boy_obj=models.Boy.objects.filter(id=5).first() 3 print(boy_obj.boyname) 4 gril_list=models.Gril.objects.filter(id__in=[3,4]) 5 boy_obj.gril_set.add(*gril_list) 6 return HttpResponse('ok')
第三张表:
总结:
- 无论是正面操作,还是反面操作,其本质是一样:1:django上,是插入对象。2:数据库本质:对相应的字段进行赋值。
- 操作第三张表的方法都是一样的。相同的方法。add可以传入单个对象、数字、列表对象、列表数字。
- ManyToMany字段的表,直接操作含有ManyToMany列来操作第三张表。
- 不含有ManyToMany的表,直接操作django创建的虚拟列:tablename_set列来操作第三张表。注:tablename为含有ManyToMany字段的表名。在数据库中表名为django的类的名字小写!
删除操作:
删除包含remove()和clear()方法。
1 def boytogril(request): 2 boy_obj=models.Boy.objects.filter(id=5).first() 3 print(boy_obj.boyname) 4 boy_obj.gril_set.clear() 5 return HttpResponse('ok')
第三张表:
clear()是将所有和id=5的jack有关系的女孩,在第三张表中都删除。
remove()指定删除某个关系的列。
1 def boytogril(request): 2 boy_obj=models.Boy.objects.filter(id=1).first() 3 print(boy_obj.boyname) 4 boy_obj.gril_set.remove(1) 5 return HttpResponse('ok')
remove(num)指定删除id=1的tom和他有关系的id=1的女孩删除掉。
删除前:
删除后:
同样可以给remove(*list)传列表。进行批量的删除。
1 def boytogril(request): 2 boy_obj=models.Boy.objects.filter(id=1).first() 3 print(boy_obj.boyname) 4 boy_obj.gril_set.remove(*[2,4]) 5 return HttpResponse('ok')
删除前:
删除后:
多对多查询
上面说过我们通过含有ManyToMany列:btog添加数据的时候,该列含有的方法中就有filter和all。我们可以通过他对第三张表进行查询。
code:
1 def boytogril(request): 2 gril_obj=models.Gril.objects.filter(id=2).first() 3 res=gril_obj.btog.all() 4 print(res) 5 for item in res: 6 print(item.boyname) 7 return HttpResponse('ok') 8 <QuerySet [<Boy: Boy object>, <Boy: Boy object>, <Boy: Boy object>]> 9 evil 10 lili 11 luc
我可以通过这样可以直接查询,如果数据库的数据量较大,进行多次sql的查询,未免会给程序和数据库带来压力。
正向查询
在ManyToMany表中,对应的列btog其实是关系表对象:gril_btog,我们可以借助它来和表boy、gril建立关系。进行查询。由于ManyToMany字段在gril表中,我们从gril表查询叫做正向查询。
1 def boytogril(request): 2 gril_obj=models.Gril.objects.filter(id=2).values('id','gril_name','btog__boyname') 3 print(gril_obj) 4 return HttpResponse('ok') 5 <QuerySet [{'btog__boyname': 'evil', 'gril_name': 'luc2', 'id': 2}, {'btog__boyname': 'lili', 'gril_name': 'luc2', 'id': 2}, {'btog__boyname': 'luc', 'gril_name': 'luc2', 'id': 2}]>
我们通过:btog__双下划线boyname 通过关系表gril_btog查询到boy表。进行跨2个表进行查询。
当然我们也可以在all,和filter里进行连表的查询。
1 def boytogril(request): 2 gril_obj=models.Gril.objects.filter(btog__boyname="evil") 3 for item in gril_obj: 4 print(item.gril_name) 5 return HttpResponse('ok') 6 luc2 7 lili
反向查询
我们通过不含有ManyToMany的字段的表查询gril表的时候,我们叫做反向查询。
但是这时候,需要注意的是:我们通过的boy表中不是通过gril_set来进行查询。
那通过什么进行查询呢?
我们可以通过django的报错提示,来查看boy表中都有哪些字段。
通过伪造不存在的列:
1 def boytogril(request): 2 boy_obj=models.Boy.objects.filter(id=2).values('id','boyname','xxx') 3 print(boy_obj) 4 return HttpResponse('ok')
所以boy表中存在的字段是gril。我们可以通过他来进行反向查询。
1 def boytogril(request): 2 boy_obj=models.Boy.objects.filter(id=2).values('id','boyname','gril__gril_name') 3 print(boy_obj) 4 return HttpResponse('ok') 5 <QuerySet [{'id': 2, 'boyname': 'evil', 'gril__gril_name': 'luc2'}, {'id': 2, 'boyname': 'evil', 'gril__gril_name': 'lili'}]>
通过django 为我们构造的虚拟列gril ,通过她和关系表、gril表建立关系,进行查询。
总结:
- 多对多查询:是通过关系表和另一张表进行查询。
- 多对一查询:是通过foreign key(是另一张表的对象)来关联第二张表。
- 可以把多对多查询理解成:进行2次多对一的双下划线查询。
- 都是通过双下划线来查找另一张表。一个是直接关联到另一张表,一个是跨一张关系表进行查询另一张表。
- 需要注意的是:插入数据的时候,我们说boy表中有虚拟列gril_set。但是查询的时候变为gril。是不一样的。
- 注意:关联的列:foreignkey、ManyToMany、对应的列从django来说是另一张表或者关系表的对象。对于数据库来说,有可能该列只是存储id值 。
update:
在多对多中,django 给咱们提供了一个更新的函数,但是这个