zoukankan      html  css  js  c++  java
  • ORM操作

    ORM

    orm的关系映射

      类----->表

      对象--->行

      方法---->字段

    操作表

      单表

    # 单表 
    class UserInfo(models.Model):
        username = models.CharField(verbose_name='用户名', max_length=32)
    单表

      ForeignKey(外键)

    # 设置外键
    class Department(models.Model):
        title = models.CharField(verbose_name='标题', max_length=32)
    
    
    class UserInfo(models.Model):
        username = models.CharField(verbose_name='用户名', max_length=32)
        depart = models.ForeignKey(verbose_name='所属部门', to="Department")
    
    
    """
    ForeignKey的参数
        on_delete:
            models.CASCADE,删除部门,则将改部门下的员工全部删除。 + 代码判断
            models.DO_NOTHING,删除部门,引发错误IntegrityError
            models.PROTECT,删除部门,引发错误ProtectedError
            models.SET_NULL,删除部门,则将改部门下的员工所属部门ID设置为空。(将FK字段设置为null=True)
            models.SET_DEFAULT,删除部门,则将改部门下的员工所属部门ID设置默认值。(将FK字段设置为default=2)
            models.SET,删除部门,则将执行set对应的函数,函数的返回值就是要给改部门下员工设置的新的部门ID。
        方法:
            models.CASCADE, 删除逻辑时,通过代码判断当前 “部门” 下是否有用户。
            models.SET_NULL,稳妥。
            沟通之后在确定。
        
        db_constraint
            默认是True,设置为False就不对关联的外键进行校验了,(不管他是否存在)
            
        limit_choices_to:可以对选项进行筛选
            bzr = models.ForeignKey(to=User,limit_choices_to={'depart__title':'教质部','id__gt':9})
            teacher = models.ForeignKey(to=User,limit_choices_to={'depart__title':'Python学院'})
    
        related_name:反向查找的字段
        
        to_field:指定关联对方的字段,默认关联对方id
        
        related_query_name:和related_name类似,但是没有他好用
    
        parent_link:没有用过
               
    
    
    """
    外键示例

       ManyToManyField(多对多)

    """
    1.自动创建第三张表(场景:关系表只有boy和girl的id):
        class Boy(models.Model):
            name = models.CharField(max_length=32)
        
        class Girl(models.Model):
            name = models.CharField(max_length=32)
            
            boy = models.ManyToManyField('Boy')
            
    手动创建第三张表(场景:除了boy和girl的id以外,还需要其他字段):
        class Boy(models.Model):
            name = models.CharField(max_length=32)
        
        class Girl(models.Model):
            name = models.CharField(max_length=32)
            
        class Boy2Girl(models.Model):
            b = models.ForeignKey(to='Boy')
            g = models.ForeignKey(to='Girl')
            
            class Meta:
                unique_together = (    
                    ("b", "g"),
                ) 
                这里设置的是设置联合唯一
    
    
    
    """
    多对多

        OneTwoOne(一对一)

    """
    OneToOneField:一对一
        应用场景:
            博客园:当你注册之后如果不申请写博客,那么你只能看博客和写评论,
                    而不能写博客,但是当你申请之后,博客园相当于给你有创建了一张表,
                    然后和你的账号进行一对一关联,这里就用到了
    """
    一对一(不常用)

    操作数据

      增删改查

    class Department(models.Model):
        title = models.CharField(verbose_name='标题', max_length=32)
    
    
    class UserInfo(models.Model):
        name = models.CharField(verbose_name='员工名称', max_length=32)
        depart = models.ForeignKey(to='Department')
    
        roles = models.ManyToManyField(to="Role")
    
    
    class Role(models.Model):
        title = models.CharField(verbose_name='标题', max_length=32)
    
    ########### 添加  #########
    
    # 添加普通字段
    Department.objects.create(title='销售部')
    Department.objects.create(**{'title':'销售部'})
    
    # 添加外键
    UserInfo.objects.create(name='姓名',depart=Department.objects.get(id=1))
    UserInfo.objects.create(name='姓名',depart_id=1)
    
    # 添加多对多
    obj = UserInfo.objects.filter(name='姓名').first()
    obj.roles.add([1,2,3])
    
    ##########  删除  ###########
    obj.delete()
    
    ########### 修改 #######
    
    # questset格式的
    UserInfo.objects.filter(id__gt=5).update(name='xx')
    
    # 对象
    obj = UserInfo.objects.filter(name='姓名').first()
    obj.roles.set([2, 3, 6, 7])
    
    #############  查询  ########
    
    # 查询到全部数据
    UserInfo.objects.all()
    # 这里返回的是一个queryset格式,里面都是字典
    UserInfo.objects.values('id', 'name')
    # 返回的是一个个的元祖
    UserInfo.objects.values_list('id', 'name')
    增删改查基本操作

      常用操作

    有时间写

      高级操作

    """
    F
    Q
    only:把括号里面的数据全部取出
        # Queryset[obj,obj,obj] 
        modes.UserInfo.objects.all().only('id','name')             # select id,name from userinfo 
        # Queryset[{},{},{}]
        modes.UserInfo.objects.all().values('id','name')         # select id,name from userinfo 
        # Queryset[(),(),()]
        modes.UserInfo.objects.all().values_list('id','name')   # select id,name from userinfo 
        
        错错错:
            result = modes.UserInfo.objects.all().only('id','name') 
            for obj in result:
                print(obj.id,obj.name,obj.age)
        原因:如果取的是没有取出的数据,你对象点也能把他取出来,但是那有相当于又去数据库查询了一下,所以最好使用only
        
    defer:把除了括号里的字段以外全部取出来
        # Queryset[obj,obj,obj]
        modes.UserInfo.objects.all().defer('name')    # select id,age from userinfo 
    
    select_related:帮助开发者进行主动连表查询
        # SELECT "app01_user"."id", "app01_user"."name", "app01_user"."depart_id" FROM "app01_user"
        result = models.User.objects.all()
        
        # SELECT "app01_user"."id", "app01_user"."name", "app01_user"."depart_id", "app01_department"."id", "app01_department"."title" FROM "app01_user" INNER JOIN "app01_department" ON ("app01_user"."depart_id" = "app01_department"."id")
        result = models.User.objects.all().select_related('depart')
        
        注意:如果以后想要获取部门名称(跨表),一定要使用select_related进行主动跨表,这样在最开始获取数据时,将当前表和关联表的所有数据都获取到。
        
        
        切记:错错错 
            result = models.User.objects.all()
            for row in result:
                print(row.name,row.depart_id,row.depart.title) # row.depart.title就会让性能大大降低
    
    prefetch_related
        # 先执行SQL: select * from user where id<100 
        # 在执行SQL: select * from depart where id in [11,20]
        result = models.User.objects.filter(id__lt=100).prefetch_related('depart')
        
    对比:
        方式一:
                result = models.User.objects.all() # 1次单表
                
                for row in result:
                    print(row.id,row.name,row.depart.title) # 100次单表
                
            方式二(小于4张表的连表操作): ***
                
                result = models.User.objects.all().select_related('depart') # 1次连表查询
                for row in result:
                    print(row.id,row.name,row.depart.title)
                
                
            方式三(大于4张表连表操作):
                
                # 先执行SQL: select * from user;
                # 在执行SQL: select * from depart where id in [11,20]
                result = models.User.objects.all().prefetch_related('depart') # 2次单表查询
                for row in result:
                    print(row.id,row.name,row.depart.title)
    
    
    
    
    
    """
    高级操作

      执行原生sql

    第一种:connection(最彻底)
        执行原生SQL,场景:复杂SQL语句
        from django.db import connection, connections # 引入模块
        # cursor = connections['db1'].cursor() :这种是如果有多个数据库可以取其中一个
        cursor = connection.cursor()  :这种是取默认的
        cursor.execute("""SELECT * from auth_user where id = %s""", [1,]) # 执行写的sql语句
        
        # row = cursor.fetchall() # 获取符合条件的所有数据,models.User.objects.all()
        row = cursor.fetchone() # 获取符合条件的第一条数据,models.User.objects.all().first()
    
    第二种:raw
        def raw(self, raw_query, params=None, translations=None, using=None):
        # 执行原生SQL
        models.UserInfo.objects.raw('select * from userinfo where id > 10 ')
    
        # 如果SQL是其他表时,必须将名字设置为当前UserInfo对象的主键列名
        models.UserInfo.objects.raw('select id as nid from 其他表')
    
        # 为原生SQL设置参数
        models.UserInfo.objects.raw('select id as nid from userinfo where nid>%s', params=[12,])
    
        # 将获取的到列名转换为指定列名
        name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'}
        Person.objects.raw('SELECT * FROM some_other_table', translations=name_map)
    
        # 指定数据库
        models.UserInfo.objects.raw('select * from userinfo', using="default")
    
    第三种:    extra        
                
    def extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
        # 构造额外的查询条件或者映射,如:子查询
        
        UserInfo.objects.extra(where=['headline ? %s'], params=['Lennon'])
        # select * from userinfo where headline > 'Lennon'
        
        UserInfo.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
        # select * from userinfo where (foo='a' OR bar = 'a') and baz = 'a'
        
        UserInfo.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))
        """
        select 
            id,
            name,
            (select col from sometable where othercol > 1) as new_id
        """
        UserInfo.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])
    3种执行原生sql语句的方法

      所有ORM操作

    所有ORM操作:
        ##################################################################
        # PUBLIC METHODS THAT ALTER ATTRIBUTES AND RETURN A NEW QUERYSET #
        ##################################################################
    
        def all(self)
            # 获取所有的数据对象
    
        def filter(self, *args, **kwargs)
            # 条件查询
            # 条件可以是:参数,字典,Q
    
        def exclude(self, *args, **kwargs)
            # 条件查询
            # 条件可以是:参数,字典,Q
    
        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 prefetch_related(self, *lookups)
            性能相关:多表连表操作时速度会慢,使用其执行多次SQL查询在Python代码中实现连表操作。
                    # 获取所有用户表
                    # 获取用户类型表where id in (用户表中的查到的所有用户ID)
                    models.UserInfo.objects.prefetch_related('外键字段')
    
    
    
                    from django.db.models import Count, Case, When, IntegerField
                    Article.objects.annotate(
                        numviews=Count(Case(
                            When(readership__what_time__lt=treshold, then=1),
                            output_field=CharField(),
                        ))
                    )
    
                    students = Student.objects.all().annotate(num_excused_absences=models.Sum(
                        models.Case(
                            models.When(absence__type='Excused', then=1),
                        default=0,
                        output_field=models.IntegerField()
                    )))
    
        def annotate(self, *args, **kwargs)
            # 用于实现聚合group by查询
    
            from django.db.models import Count, Avg, Max, Min, Sum
    
            v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id'))
            # SELECT u_id, COUNT(ui) AS `uid` FROM UserInfo GROUP BY u_id
    
            v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')).filter(uid__gt=1)
            # SELECT u_id, COUNT(ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1
    
            v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id',distinct=True)).filter(uid__gt=1)
            # SELECT u_id, COUNT( DISTINCT ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1
    
        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 extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
            # 构造额外的查询条件或者映射,如:子查询
            
            UserInfo.objects.extra(where=['headline ? %s'], params=['Lennon'])
            # select * from userinfo where headline > 'Lennon'
            
            UserInfo.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
            # select * from userinfo where (foo='a' OR bar = 'a') and baz = 'a'
            
            UserInfo.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))
                """
                select 
                    id,
                    name,
                    (select col from sometable where othercol > 1) as new_id
                """
            UserInfo.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])
    
         def reverse(self):
            # 倒序
            models.UserInfo.objects.all().order_by('-nid').reverse()
            # 注:如果存在order_by,reverse则是倒序,如果多个排序则一一倒序
    
    
         def defer(self, *fields):
            models.UserInfo.objects.defer('username','id')
            或
            models.UserInfo.objects.filter(...).defer('username','id')
            #映射中排除某列数据
    
         def only(self, *fields):
            #仅取某个表中的数据
             models.UserInfo.objects.only('username','id')
             或
             models.UserInfo.objects.filter(...).only('username','id')
    
         def using(self, alias):
             指定使用的数据库,参数为别名(setting中的设置)
             
             models.UserInfo.objects.filter(id=5).using('db1')
    
    
        ##################################################
        # PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS #
        ##################################################
    
        def raw(self, raw_query, params=None, translations=None, using=None):
            # 执行原生SQL
            models.UserInfo.objects.raw('select * from userinfo where id > 10 ')
    
            # 如果SQL是其他表时,必须将名字设置为当前UserInfo对象的主键列名
            models.UserInfo.objects.raw('select id as nid from 其他表')
    
            # 为原生SQL设置参数
            models.UserInfo.objects.raw('select id as nid from userinfo where nid>%s', params=[12,])
    
            # 将获取的到列名转换为指定列名
            name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'}
            Person.objects.raw('SELECT * FROM some_other_table', translations=name_map)
    
            # 指定数据库
            models.UserInfo.objects.raw('select * from userinfo', using="default")
    
        ################### 原生SQL ###################
        from django.db import connection, connections
        cursor = connection.cursor()  # cursor = connections['default'].cursor()
        cursor.execute("""SELECT * from auth_user where id = %s""", [1])
        row = cursor.fetchone() # fetchall()/fetchmany(..)
    
    
        def values(self, *fields):
            # 获取每行数据为字典格式
    
        def values_list(self, *fields, **kwargs):
            # 获取每行数据为元祖
    
        def dates(self, field_name, kind, order='ASC'):
            # 根据时间进行某一部分进行去重查找并截取指定内容
            # kind只能是:"year"(年), "month"(年-月), "day"(年-月-日)
            # order只能是:"ASC"  "DESC"
            # 并获取转换后的时间
                - year : 年-01-01
                - month: 年-月-01
                - day  : 年-月-日
    
            models.DatePlus.objects.dates('ctime','day','DESC')
    
        def datetimes(self, field_name, kind, order='ASC', tzinfo=None):
            # 根据时间进行某一部分进行去重查找并截取指定内容,将时间转换为指定时区时间
            # kind只能是 "year", "month", "day", "hour", "minute", "second"
            # order只能是:"ASC"  "DESC"
            # tzinfo时区对象
            models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.UTC)
            models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.timezone('Asia/Shanghai'))
    
            """
            pip3 install pytz
            import pytz
            pytz.all_timezones
            pytz.timezone(‘Asia/Shanghai’)
            """
    
        def none(self):
            # 空QuerySet对象
    
    
        ####################################
        # METHODS THAT DO DATABASE QUERIES #
        ####################################
    
        def aggregate(self, *args, **kwargs):
           # 聚合函数,获取字典类型聚合结果
           from django.db.models import Count, Avg, Max, Min, Sum
           result = models.UserInfo.objects.aggregate(k=Count('u_id', distinct=True), n=Count('nid'))
           ===> {'k': 3, 'n': 4}
    
        def count(self):
           # 获取个数
    
        def get(self, *args, **kwargs):
           # 获取单个对象
    
        def create(self, **kwargs):
           # 创建对象
    
        def bulk_create(self, objs, batch_size=None):
            # 批量插入
            # batch_size表示一次插入的个数
            objs = [
                models.DDD(name='r11'),
                models.DDD(name='r22')
            ]
            models.DDD.objects.bulk_create(objs, 10)
    
        def get_or_create(self, defaults=None, **kwargs):
            # 如果存在,则获取,否则,创建
            # defaults 指定创建时,其他字段的值
            obj, created = models.UserInfo.objects.get_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 2})
    
        def update_or_create(self, defaults=None, **kwargs):
            # 如果存在,则更新,否则,创建
            # defaults 指定创建时或更新时的其他字段
            obj, created = models.UserInfo.objects.update_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 1})
    
        def first(self):
           # 获取第一个
    
        def last(self):
           # 获取最后一个
    
        def in_bulk(self, id_list=None):
           # 根据主键ID进行查找
           id_list = [11,21,31]
           models.DDD.objects.in_bulk(id_list)
           
           models.User.objects.filter(id__in=[11,21,31])
    
        def delete(self):
           # 删除
    
        def update(self, **kwargs):
            # 更新
    
        def exists(self):
           # 是否有结果
            pass
    orm的所有操作

      

  • 相关阅读:
    SVN 初级教程
    572 node包管理工具
    571 node的events模块
    570 node内置模块fs
    569 node内置模块path
    568 node之JavaScript模块化:exports,module.exports,import,对象的引用赋值,require查找规则,export、import关键字,CommonJS的加载过程,ES Module加载过程
    567 node概述:Node程序传递参数,常见的全局对象,特殊的全局对象
    566 手写37个 原生JavaScript 系列汇总(含promise A+)
    565 手写promise源码
    564 函数的防抖和节流
  • 原文地址:https://www.cnblogs.com/chunqiuyu/p/9915696.html
Copyright © 2011-2022 走看看