django--ORM操作
创建数据库 .related_name .related_query_name # 表和表之间可以自关联 多对多自关联 --> 互粉 related_name 一对多自关联 --> 评论楼 related_name 操作数据库 .all .values .values_list .delete .filter .update .create .m.add .m.set .m.clear .m.remove .only .defer .extra .raw 原生SQL select_related prefetch_related
<1> all(): 查询所有结果 <2> filter(**kwargs): 它包含了与所给筛选条件相匹配的对象 <3> get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个, 如果符合筛选条件的对象超过一个或者没有都会抛出错误。 <4> exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象 <5> order_by(*field): 对查询结果排序 <6> reverse(): 对查询结果反向排序 <8> count(): 返回数据库中匹配查询(QuerySet)的对象数量。 <9> first(): 返回第一条记录 <10> last(): 返回最后一条记录 <11> exists(): 如果QuerySet包含数据,就返回True,否则返回False <12> values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列 model的实例化对象,而是一个可迭代的字典序列 <13> values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列 <14> distinct(): 从返回结果中剔除重复纪录
ORM中注入原生字符串使用row()方法,详见
Book.objects.filter(price__in=[100,200,300]) Book.objects.filter(price__gt=100) Book.objects.filter(price__lt=100) Book.objects.filter(price__range=[100,200]) Book.objects.filter(title__contains="python") Book.objects.filter(title__icontains="python") Book.objects.filter(title__startswith="py") Book.objects.filter(pub_date__year=2012)
1 Model连表操作重点: 2 a、索引 3 b、一对多:参数on_delete 4 c、多对多: 5 -自动创建、手动创建 6 -自关联
PS:FK和M2M加上参数related_name
django默认使用sqlite数据库,使用mysql需做配置:
settings.py: DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'day19', 'USER': 'root', 'PASSWORD': 'python', 'HOST': 'localhost', 'PORT': '3306', } } 工程的init.py增加:(django2.x不用) import pymysql pymysql.install_as_MySQLdb()
单表
建表
1 class UserInfo(models.Model): 2 username = models.CharField(max_length=32) 3 password = models.CharField(max_length=32)
增
1 #创建数据,三种方式 2 #models.UserInfo.objects.create(username='root',password='123',) 3 dic = {'username':'eric','password':'22'} 4 models.UserInfo.objects.create(**dic) 5 # obj=models.UserInfo(username='alex',password='11',) 6 # obj.save()
查
1 #查全部 2 result = models.UserInfo.objects.all()#查全部 3 #返回的result是QuerySet类型,Django提供,类似于列表 4 #[obj(id,username,password),obj(),obj()] 5 #每个obj都是一个对象,是一行元素 6 7 #按条件查 8 result = models.UserInfo.objects.filter(username='root') 9 for row in result: 10 print(row.id,row.username,row.password) 11 print(result) 12 models.UserInfo.objects.filter(id=nid).first()#获取单条数据 是一个model对象 13 14 models.UserInfo.objects.filter(id=1) 15 models.UserInfo.objects.filter(id=1,name='root') 16 result = models.UserInfo.objects.filter(id__gt=1)#所有id>1的
删
1 models.UserInfo.objects.filter(username='alex').delete() 2 models.UserInfo.objects.filter(id=1).delete()
改
1 models.UserInfo.objects.all().update(password='666')#修改所有字段 2 models.UserInfo.objects.filter(id=3).update(password='999')#筛选修改
外键(一对多)
建表
1 class Classes(models.Model): 2 '''班级表''' 3 title=models.CharField(max_length=32) 4 5 class Student(models.Model): 6 '''学生表''' 7 username = models.CharField(max_length=32) 8 age = models.IntegerField() 9 gender = models.BooleanField() 10 #gender = models.NullBooleanField() #可以不填 11 cs = models.ForeignKey(Classes)
班级: 学生:
id name id username age gender cs_id
1 3班 1 东北 18 男 1
2 6班 2 东北1 118 男 2
3 东北2 118 男 1
增加
Student.objects.create(username='北',age=18,gender='男',cs_id=1) Student.objects.create(username='东北',age=18,gender='男',cs= Classes.objects.filter(id=1).first() )
查看
ret = Student.objects.all() # [] # [ obj(..),] # [ obj(1 东北 18 男 1),obj(2 东北1 118 男 2),obj(..),] for item in ret: print(item.id) print(item.username) print(item.age) print(item.gender) print(item.cs_id) print(item.cs.id) print(item.cs.name)
删除
1 Student.objects.filter(id=1).delete() 2 Student.objects.filter(cs_id=1).delete() 3 4 cid = input('请输入班级ID') 5 Student.objects.filter(cs_id=cid).delete() 6 7 cname = input('请输入班级名称') 8 Student.objects.filter(cs_id=cid).delete() 9 Student.objects.filter(cs__name=cname).delete()filter()#筛选条件里想跨表只能用双下划线
示例
找所有学生的姓名以及其所在班级名称,QuerySet
stu_list = Student.objects.all() select * from tb; [obj,obj,obj,obj] stu_list = Student.objects.all().values("id",'username') select id,username from tb; [{"id":1,'username':'xx'},{id:'',username:''}] stu_list = Student.objects.all().values_list("id",'username') [(1,'root'), (2,'alex')] stu_list = Student.objects.all().values('username',"cs__name") for row in stu_list: print(row['username'],row['cs__name']) stu_list = Student.objects.all().values('username',"cs__titile",“cs__fk__name”)
1 #按行查找 2 models.Classes.objects.all() #所有行 3 models.Classes.objects.filter(‘条件’) #按条件查某些行 4 models.Classes.objects.filter(‘条件’)。first() #满足查找条件的第一行 5 #行+列查找 6 models.Classes.objects.all().values(‘列名1’,‘列名2’,...) 7 models.Classes.objects.filter().values()
找2班的所有学生
假设有班级表和学生表,学生表外键关联班级
class Classes(models.Model): '''班级表''' title=models.CharField(max_length=32) class Student(models.Model): '''学生表''' username = models.CharField(max_length=32) age = models.IntegerField() gender = models.BooleanField() cs = models.ForeignKey(Classes) 班级: 学生: id name id username age gender cs_id 1 2班 1 小东 18 1 1 2 3班 2 中东 30 1 2 3 4班 3 大东 50 1 1 4 老东 60 1 1
正向查找
# 从学生表找所有二班的 学生表有班级字段 obj = models.Student.objects.filter(cs__title='2班') #找到所有二班学生的信息 for row in obj: print(row.username) #从对象里取信息 obj = models.Student.objects.filter(cs__title='2班').values('username') #直接获取特定信息 print(obj)
反向查找
#从班级表找所有二班的 班级表没有学生字段 ret = models.Classes.objects.filter(title='2班').first() print(ret.id , ret.title) #班级表能看到的字段 print(ret.student_set) #跨到学生表 隐藏的字段 print(ret.student_set.all()) #找到所有二班学生的信息 print(ret.student_set.all().values('username')) #打印名字
总结:
1. 类代表数据库表
2. 类的对象代指数据库的一行记录
3. FK字段代指关联表中的一行数据(类的对象)
4.
- 正向:fk字段 (*****)
- 反向:小写类名_set(默认) ==> related_name='ssss'
class Student(models.Model): ... cs = models.ForeignKey(Classes,related_name='alex') #定义ForeignKey时可设置related_name,操作Classes表(被关联表)时,可以当字段用 ret = models.Classes.objects.filter(title='2班').first() print(ret.alex.all())
5. 谁是主表?就全部列出其数据
models.Student.objects.all().values('username', 'cs__titile')
models.Classes.objects.all().values('titile', 'ssss__username')
4. M2M字段,自动生成第三张表;依赖关联表对第三张表间接操作
多对多
创建3张表,其中一张m2m
1 class Classes(models.Model): 2 '''班级表''' 3 title=models.CharField(max_length=32) 4 m = models.ManyToManyField("Teachers") 5 # django自动生成多对多,在Classes或Teachers创建都行 6 #因为这里Teachers还没创建,所以加引号 7 class Teachers(models.Model): 8 '''老师表''' 9 name = models.CharField(max_length=32) 10 # m = models.ManyToManyField(Classes)也可以在这里创建多对多
class C2T(models.Model): '''自定义设置多对多表''' cid = models.ForeignKey(Classes) tid = models.ForeignKey(Teachers) class Meta: unique_together=[ ('cid','tid'), #两列联合唯一,即不能有两行是重复的 #M2M字段就有该方法 ]
生成三张表
班级: 老师:
id title id name
1 3班 1 Alex
2 4班 2 Eric
3 5班 3 Jack
老师班级关系表(类):
id 班级id 老师id
1 1 2
2 1 3
4 2 2
5 2 3
6 2 4
7 1 5
增
1 obj = Classes.objects.filter(id=1).first() #1 3班 #获取班级对象 2 obj.m.add(2) #给班级安排老师 3 obj.m.add(4,3) #以列表形式一次增加多个
删
1 obj = Classes.objects.filter(id=1).first() #1 3班 2 # 删除 3 obj.m.remove(4,3) 4 # 清空 5 obj.m.clear() 6 # 重置 7 obj.m.set([2,3,5]) #对于已存在的多对多关系不做修改,其余的删掉,在最后新建 8 如1班已有2,3,4老师,则把4老师对应多对多关系删掉,新建一个1班对应5老师 9 原有: 10 id 班级id 老师id 11 1 1 2 12 2 1 3 13 4 1 4 14 执行obj.m.set([2,3,5]) 后 15 id 班级id 老师id 16 1 1 2 17 2 1 3 18 19 5 1 5
查第三张表
1 # 把3班的所有老师列举 2 obj = Classes.objects.filter(id=1).frist() 3 obj.id 4 obj.titile 5 ret = obj.m.all() # 第三张表 6 # ret是一个 [ 老师1(id,name),obj(id,name) ]
班级表和老师表跨表查询
班级跨表查老师时,通过obj.m 老师跨表查班级,在设置m2m时增加related_name属性,可以认为在老师表增加了cls字段,通过cls查班级 class Classes(models.Model): '''班级表''' m = models.ManyToManyField("Teachers",related_name='cls')
def select_related(self, *fields) #有外键时减少数据库查询次数 性能相关:表之间进行join连表操作,一次性获取关联的数据。 model.tb.objects.all().select_related() model.tb.objects.all().select_related('外键字段') model.tb.objects.all().select_related('外键字段__外键字段') def distinct(self, *field_names) # 用于distinct去重 models.UserInfo.objects.values('nid').distinct() # select distinct nid from userinfo 注:只有在PostgreSQL中才能使用distinct进行去重 def order_by(self, *field_names) # 用于排序 models.UserInfo.objects.all().order_by('-id','age') def reverse(self): # 倒序 models.UserInfo.objects.all().order_by('-nid').reverse() # 注:如果存在order_by,reverse则是倒序,如果多个排序则一一倒序 def extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None) # 构造额外的查询条件或者映射,如:子查询 Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,)) Entry.objects.extra(where=['headline=%s'], params=['Lennon']) Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"]) Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid']) def defer(self, *fields): models.UserInfo.objects.defer('username','id') 或 models.UserInfo.objects.filter(...).defer('username','id') #映射中排除某列数据 def only(self, *fields): #与.values()功能相同,内部数据不同 #仅取某个表中的数据 [obj,obj,...] models.UserInfo.objects.only('username','id') 或 models.UserInfo.objects.filter(...).only('username','id')
models.UserInfo.objects.all() a. select_related('跨表字段') : 一次连表查询获取所有的数据 models.UserInfo.objects.select_related('ut') # 连表查询性能低 UserInfo,UserType b. prefetch_related 与select_related功能相同,不同的是两次SQL语句 models.UserInfo.objects.prefetch_related('ut') # select * from userinfo where id < 20 # 计算获取到的所有用户的用户类型ID [1,] # select * from usertype where id in [1,]

浙公网安备 33010602011771号