zoukankan      html  css  js  c++  java
  • django-强大的ORM

    一、ORM简介

    (对象关系映射:object relationship mapping)

    • MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库
    • ORM是“对象-关系-映射”的简称,主要任务是:
      • 根据对象的类型生成表结构
      • 将对象、列表的操作,转换为sql语句
      • 将sql查询到的结果转换为对象、列表(其实这里说列表并不合适,有过django开发经验的应该都会知道其实是一种queryset对象,而queryset对象提供的api也与列表或者集合大不不同)
    • 这极大的减轻了开发人员的工作量,不需要面对因数据库变更而导致的无效劳动
    • Django中的模型包含存储数据的字段和约束,对应着数据库中唯一的表

    二、ORM操作以及Queryset API

    这里主要解释ORM的各种操作,以及Queryset类型对应的各种接口参数不同对应的sql语句。

    1、基本操作

    # 获取所有数据,对应SQL:select * from User
    User.objects.all()
    
    # 匹配,对应SQL:select * from User where name = '蔚蓝'
    User.objects.filter(name='蔚蓝')
    
    # 不匹配,对应SQL:select * from User where name != '蔚蓝'
    User.objects.exclude(name='蔚蓝')
    
    # 获取单条数据(有且仅有一条,id唯一),对应SQL:select * from User where id = 724
    User.objects.get(id=123)
    

    2、常用操作

    # 获取总数,对应SQL:select count(1) from User
    User.objects.count()
    
    # 获取总数,对应SQL:select count(1) from User where name = '蔚蓝'
    User.objects.filter(name='蔚蓝').count()
    
    # 大于,>,对应SQL:select * from User where id > 724
    User.objects.filter(id__gt=724)
    
    # 大于等于,>=,对应SQL:select * from User where id >= 724
    User.objects.filter(id__gte=724)
    
    # 小于,<,对应SQL:select * from User where id < 724
    User.objects.filter(id__lt=724)
    
    # 小于等于,<=,对应SQL:select * from User where id <= 724
    User.objects.filter(id__lte=724)
    
    # 同时大于和小于, 1 < id < 10,对应SQL:select * from User where id > 1 and id < 10
    User.objects.filter(id__gt=1, id__lt=10)
    
    # 包含,in,对应SQL:select * from User where id in (11,22,33)
    User.objects.filter(id__in=[11, 22, 33])
    
    # 不包含,not in,对应SQL:select * from User where id not in (11,22,33)
    User.objects.exclude(id__in=[11, 22, 33])
    
    # 为空:isnull=True,对应SQL:select * from User where pub_date is null
    User.objects.filter(pub_date__isnull=True)
    
    # 不为空:isnull=False,对应SQL:select * from User where pub_date is not null
    User.objects.filter(pub_date__isnull=True)
    
    # 匹配,like,大小写敏感,对应SQL:select * from User where name like '%sre%',SQL中大小写不敏感
    User.objects.filter(name__contains="sre")
    
    # 匹配,like,大小写不敏感,对应SQL:select * from User where name like '%sre%',SQL中大小写不敏感
    User.objects.filter(name__icontains="sre")
    
    # 不匹配,大小写敏感,对应SQL:select * from User where name not like '%sre%',SQL中大小写不敏感
    User.objects.exclude(name__contains="sre")
    
    # 不匹配,大小写不敏感,对应SQL:select * from User where name not like '%sre%',SQL中大小写不敏感
    User.objects.exclude(name__icontains="sre")
    
    # 范围,between and,对应SQL:select * from User where id between 3 and 8
    User.objects.filter(id__range=[3, 8])
    
    # 以什么开头,大小写敏感,对应SQL:select * from User where name like 'sh%',SQL中大小写不敏感
    User.objects.filter(name__startswith='sre')
    
    # 以什么开头,大小写不敏感,对应SQL:select * from User where name like 'sh%',SQL中大小写不敏感
    User.objects.filter(name__istartswith='sre')
    
    # 以什么结尾,大小写敏感,对应SQL:select * from User where name like '%sre',SQL中大小写不敏感
    User.objects.filter(name__endswith='sre')
    
    # 以什么结尾,大小写不敏感,对应SQL:select * from User where name like '%sre',SQL中大小写不敏感
    User.objects.filter(name__iendswith='sre')
    
    # 排序,order by,正序,对应SQL:select * from User where name = '蔚蓝' order by id
    User.objects.filter(name='蔚蓝').order_by('id')
    
    # 多级排序,order by,先按name进行正序排列,如果name一致则再按照id倒叙排列
    User.objects.filter(name='蔚蓝').order_by('name','-id')
    
    # 排序,order by,倒序,对应SQL:select * from User where name = '蔚蓝' order by id desc
    User.objects.filter(name='蔚蓝').order_by('-id')
    

    3、进阶操作

    # limit,对应SQL:select * from User limit 3;
    User.objects.all()[:3]
    
    # limit,取第三条以后的数据,没有对应的SQL,类似的如:select * from User limit 3,10000000,从第3条开始取数据,取10000000条(10000000大于表中数据条数)
    User.objects.all()[3:]
    
    # offset,取出结果的第10-20条数据(不包含10,包含20),也没有对应SQL,参考上边的SQL写法
    User.objects.all()[10:20]
    
    # 分组,group by,对应SQL:select username,count(1) from User group by username;
    from django.db.models import Count
    User.objects.values_list('username').annotate(Count('id'))
    
    # 去重distinct,对应SQL:select distinct(username) from User
    User.objects.values('username').distinct().count()
    
    # filter多列、查询多列,对应SQL:select username,fullname from accounts_user
    User.objects.values_list('username', 'fullname')
    
    # filter单列、查询单列,正常values_list给出的结果是个列表,里边里边的每条数据对应一个元组,当只查询一列时,可以使用flat标签去掉元组,将每条数据的结果以字符串的形式存储在列表中,从而避免解析元组的麻烦
    User.objects.values_list('username', flat=True)
    
    # int字段取最大值、最小值、综合、平均数
    from django.db.models import Sum,Count,Max,Min,Avg
    
    User.objects.aggregate(Count(‘id’))
    User.objects.aggregate(Sum(‘age’))
    

    4、时间字段

    # 匹配日期,date
    User.objects.filter(create_time__date=datetime.date(2018, 8, 1))
    User.objects.filter(create_time__date__gt=datetime.date(2018, 8, 2))
    
    # 匹配年,year
    User.objects.filter(create_time__year=2018)
    User.objects.filter(create_time__year__gte=2018)
    
    # 匹配月,month
    User.objects.filter(create_time__month__gt=7)
    User.objects.filter(create_time__month__gte=7)
    
    # 匹配日,day
    User.objects.filter(create_time__day=8)
    User.objects.filter(create_time__day__gte=8)
    
    # 匹配周,week_day
     User.objects.filter(create_time__week_day=2)
    User.objects.filter(create_time__week_day__gte=2)
    
    # 匹配时,hour
    User.objects.filter(create_time__hour=9)
    User.objects.filter(create_time__hour__gte=9)
    
    # 匹配分,minute
    User.objects.filter(create_time__minute=15)
    User.objects.filter(create_time__minute_gt=15)
    
    # 匹配秒,second
    User.objects.filter(create_time__second=15)
    User.objects.filter(create_time__second__gte=15)
    
    
    # 按天统计归档
    today = datetime.date.today()
    select = {'day': connection.ops.date_trunc_sql('day', 'create_time')}
    deploy_date_count = Task.objects.filter(
        create_time__range=(today - datetime.timedelta(days=7), today)
    ).extra(select=select).values('day').annotate(number=Count('id'))
    

    5、Q 的使用

    Q对象可以对关键字参数进行封装,从而更好的应用多个查询,可以组合&(and)、|(or)、~(not)操作符

    from django.db.models import Q
    
    User.objects.filter(
        Q(role__startswith='sre_'),
        Q(name='散人') | Q(name='`蔚蓝')
    )
    
    对应的SQL语句
    select * from User where role like 'sre_%' and (name='散人' or name='蔚蓝')
    

    通常更多的时候我们用Q来做搜索逻辑,比如前台搜索框输入一个字符,后台去数据库中检索标题或内容中是否包含

    _s = request.GET.get('search')
    
    _t = Blog.objects.all()
    if _s:
        _t = _t.filter(
            Q(title__icontains=_s) |
            Q(content__icontains=_s)
        )
    
    return _t
    

    6、外键:ForeignKey

    表结构:

    class Role(models.Model):
        name = models.CharField(max_length=16, unique=True)
    
    
    class User(models.Model):
        username = models.EmailField(max_length=255, unique=True)
        role = models.ForeignKey(Role, on_delete=models.CASCADE)
    

    正向查询:

    # 查询用户的角色名
    _t = User.objects.get(username='蔚蓝')
    _t.role.name
    

    反向查询:

    # 查询角色下包含的所有用户
    _t = Role.objects.get(name='Role03')
    _t.user_set.all()
    

    另一种反向查询的方法:

    _t = Role.objects.get(name='Role03')
    

    这种方法比上一种_set的方法查询速度要快

    User.objects.filter(role=_t)
    

    第三种反向查询的方法:

    如果外键字段有related_name属性,例如models如下:
    
    class User(models.Model):
        username = models.EmailField(max_length=255, unique=True)
        role = models.ForeignKey(Role, on_delete=models.CASCADE,related_name='roleUsers')
    那么可以直接用related_name属性取到某角色的所有用户
    
    _t = Role.objects.get(name = 'Role03')
    _t.roleUsers.all()
    

    7、M2M:ManyToManyField

    表结构:

    class Group(models.Model):
        name = models.CharField(max_length=16, unique=True)
    
    class User(models.Model):
        username = models.CharField(max_length=255, unique=True)
        groups = models.ManyToManyField(Group, related_name='groupUsers')
    

    正向查询:

    # 查询用户隶属组
    _t = User.objects.get(username = '蔚蓝')
    _t.groups.all()
    

    反向查询:

    # 查询组包含用户
    _t = Group.objects.get(name = 'groupC')
    _t.user_set.all()
    

    同样M2M字段如果有related_name属性,那么可以直接用下边的方式反查

    _t = Group.objects.get(name = 'groupC')
    _t.groupUsers.all()
    

    8、get_object_or_404

    正常如果我们要去数据库里搜索某一条数据时,通常使用下边的方法:

    _t = User.objects.get(id=734)
    

    但当id=724的数据不存在时,程序将会抛出一个错误

    abcer.models.DoesNotExist: User matching query does not exist.
    

    为了程序兼容和异常判断,我们可以使用下边两种方式:

    方式一:get改为filter

    _t = User.objects.filter(id=724)
    

    取出_t之后再去判断_t是否存在

    方式二:使用get_object_or_404

    from django.shortcuts import get_object_or_404
    
    _t = get_object_or_404(User, id=724)
    # get_object_or_404方法,它会先调用django的get方法,如果查询的对象不存在的话,则抛出一个Http404的异常
    

    实现方法类似于下边这样:

    from django.http import Http404
    
    try:
        _t = User.objects.get(id=724)
    except User.DoesNotExist:
        raise Http404
    

    9、get_or_create

    顾名思义,查找一个对象如果不存在则创建,如下:

    object, created = User.objects.get_or_create(username='蔚蓝')
    

    返回一个由object和created组成的元组,其中object就是一个查询到的或者是被创建的对象,created是一个表示是否创建了新对象的布尔值

    实现方式类似于下边这样:

    try:
        object = User.objects.get(username='蔚蓝')
    
        created = False
    exception User.DoesNoExist:
        object = User(username='蔚蓝')
        object.save()
    
        created = True
    
    returen object, created
    

    补充:上面提到了get_or_create是如果查找不到就创建,那么想要进行更新一条记录,如果如果没有就创建呢?显然就是update_or_create

    10、执行原生SQL

    Django中能用ORM的就用它ORM吧,不建议执行原生SQL,可能会有一些安全问题,如果实在是SQL太复杂ORM实现不了,那就看看下边执行原生SQL的方法,跟直接使用pymysql基本一致了

    from django.db import connection
    
    with connection.cursor() as cursor:
        cursor.execute('select * from accounts_User')
        row = cursor.fetchall()
    
    return row
    

    注意这里表名字要用app名+下划线+model名的方式

    三、总结

    有了django强大的orm和queryset提供的多种api,我们可以基于数据库中的数据做各种增删改查,根据条件过滤筛选排序,省去了自己在视图函数中写业务逻辑的麻烦,即使提供的方法不能满足要求,也可以自己利用数据库驱动,书写原生SQL语句对数据库操作,十分方便。数据库可以是各种关系型数据库,mysql ,django自带的小型sqlite,或者是SQL Server等。只需在settings配置文件中,配置数据库文件即可。

  • 相关阅读:
    Postgresql HStore 插件试用小结
    postgres-xl 安装与部署 【异常处理】ERROR: could not open file (null)/STDIN_***_0 for write, No such file or directory
    GPDB 5.x PSQL Quick Reference
    postgresql 数据库schema 复制
    hive 打印日志
    gp与 pg 查询进程
    jquery table 发送两次请求 解惑
    python 字符串拼接效率打脸帖
    postgresql 日期类型处理实践
    IBM Rational Rose软件下载以及全破解方法
  • 原文地址:https://www.cnblogs.com/welan/p/9858747.html
Copyright © 2011-2022 走看看