django--ORM操作

更多     yuan

django-Model操作

创建数据库
    .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():            从返回结果中剔除重复纪录
查询API

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()
配置mysql

单表

建表

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”)
View Code
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,]
性能相关:

 

posted @ 2018-03-13 22:36  web123  阅读(101)  评论(0)    收藏  举报