zoukankan      html  css  js  c++  java
  • Django ORM相关操作

    Django ORM相关操作

    在Python脚本中调用Django环境

    很多情况下,在做测试的时候需要在Python脚本进行,此时若想成功运行需要导入Django环境配置,否则运行不成功。

    import os
    
    if __name__ == '__main__':
        # 导入配置环境,记不住就去manage.py中找
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "ormday69.settings")
        # 启动Django
        import django
        django.setup()
    
        # 要进行的操作
        from app01 import models
        .....
        
    

    Django终端打印SQL语句

    在运行相应的操作后会在终端打印相应的SQL语句
    在Django项目的settings.py文件中,在最后复制粘贴如下代码:

    LOGGING = {
        'version': 1,
        'disable_existing_loggers': False,
        'handlers': {
            'console':{
                'level':'DEBUG',
                'class':'logging.StreamHandler',
            },
        },
        'loggers': {
            'django.db.backends': {
                'handlers': ['console'],
                'propagate': True,
                'level':'DEBUG',
            },
        }
    }
    

    一般操作

    基本的语法是:models.类名.objects.函数名()

    必知必会13个

    all()

    1. 功能:
      查询表中的所有结果
    2. 使用方式:
      models.Person.objects.all()
    3. 返回内容:
      QuerySet

    get()

    1. 功能:
      返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。
    2. 使用方式:
      models.Person.objects.get(id=1)
    3. 返回内容:
      Object

    filter(**kwargs)

    1. 功能:
      返回所给筛选条件相匹配的对象,返回的是个类似于列表一样的QuerySet对象。如果没有找到不会报错,会返回一个空的QuerySet对象,及时只有一个返回值照样返回QuerySet,想要取到某一个值可以使用索引。

    2. 使用方式:

      ret = models.Person.objects.filter()
      
      ret = models.Person.objects.filter()
      ret[0]
      
    3. 返回内容:
      QuerySet

    注意比较get方法和filter方法的不同之处

    exclude(**kwargs)

    1. 功能:
      与所给筛选条件不匹配的对象
    2. 使用方式:
      ret = models.Person.objects.exclude(id=1)
    3. 返回内容:
      QuerySet

    values(*field)

    1. 功能:
      返回一个可迭代的字典序列,每一个都是 {"字段":值} 的形式
      参数为数据表的字段,如果没有字段则返回所有字段
    2. 使用方式:
      ret = models.Person.objects.values()
    3. 返回内容:
      特殊的QuerySet

    values_list(*field)

    1. 功能:
      它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
    2. 使用方式:
      ret = models.Person.objects.values_list()
    3. 返回内容:
      特殊的QuerySet

    order_by(*field)

    1. 功能:
      对查询结果排序
      1. 有参数,按照参数字段排序

      2. 没有参数,类在元数据中设置了默认排序方式
        按照元数据的默认排序方式,元数据设置方式如下:

        class Person(models.Model):
            name = models.CharField(max_length=32)
            age = models.IntegerField(default=18)
            birthday = models.DateField(auto_now_add=True)
        
            def __str__(self):
                return "<Object:Person>{}".format(self.name)
        
            class Meta:
                ordering=("birthday", )
        
      3. 没有参数,且没有设置元数据
        按照原有顺序输出,不排序

    2. 使用方式:
      ret = models.Person.objects.order_by()
    3. 返回内容:
      QuerySet

    reverse()

    1. 功能:
      对查询结果反向排序,请注意reverse()通常只能在具有已定义顺序的QuerySet上调用(在model类的Meta中指定ordering或调用order_by()方法)。
    2. 使用方式:
      ret = models.Person.objects.reverse()
    3. 返回内容:
      QuerySet

    count()

    1. 功能:
      返回数据库中匹配查询(QuerySet)的对象数量。
    2. 使用方式:
      ret = models.Person.objects.count()
    3. 返回内容:
      数字

    first()

    1. 功能:
      返回第一条记录
    2. 使用方式:
      ret = models.Person.objects.first()
    3. 返回内容:
      具体的对象

    last()

    1. 功能:
      返回最后一条记录
    2. 使用方式:
      ret = models.Person.objects.last()
    3. 返回内容:
      具体的对象

    exists()

    1. 功能:
      如果QuerySet包含数据,就返回True,否则返回False
    2. 使用方式:
      ret = models.Person.objects.exists()
    3. 返回内容:
      布尔值

    distinct()

    1. 功能:
      从返回结果中剔除重复纪录(如果你查询跨越多个表,可能在计算QuerySet时得到重复的结果。此时可以使用distinct(),注意只有在PostgreSQL中支持按字段去重。)

    2. 使用方式:

    3. 返回内容:

    单表查询之神奇的双下划线

    只能用在前面提到的filter函数中使用,方式为:字段+双下划线+=+值

    __lt     __gt

    models.Person.objects.filter(id__gt=2, id__lt=5) # 获取 id 大于 2 且小于 5 的值

    __in

    models.Person.objects.filter(id__in=[1, 2, 3]) # 获取 id 等于 11、22、33 的数据

    models.Person.objects.exclude(id__in=[1, 2, 3]) # 获取 id 不等于 11、22、33 的数据

    __contains

    models.Person.objects.filter(name__contains="ban") # 获取 name 字段包含 "ban" 的

    models.Person.objects.filter(name__icontains="ban") # icontains 对大小写不敏感

    __range

    models.Person.objects.filter(id__range=(1, 3)) # id 范围是 1 到 3 的,等价于 SQL 的 bettwen and

    date字段有:__year, __month, __day

    models.Person.objects.filter(birthday__day=6) # 表示 birthday 字段中日为 6

    其他关于字符串的还有

    startswith,istartswith, endswith, iendswith

    ForeignKey操作

    正向查找

    1. 对象查找(跨表)
      语法:

      对象.关联字段.字段

      示例:

      book_obj = models.Book.objects.first()  # 第一本书对象
      print(book_obj.publisher)  # 得到这本书关联的出版社对象
      print(book_obj.publisher.name)  # 得到出版社对象的名称
      
    2. 字段查找(跨表)
      根据双下划线跨表查询,双下划线就代表跨了一张表
      语法:

      关联字段__字段

      示例:

      print(models.Book.objects.values_list("publisher__name"))
      

    反向查询

    1. 对象查找
      语法:

      obj.表名_set

      示例:

      publisher_obj = models.Publisher.objects.first()  # 找到第一个出版社对象
      books = publisher_obj.book_set.all()  # 找到第一个出版社出版的所有书
      titles = books.values_list("title")  # 找到第一个出版社出版的所有书的书名
      
    2. 字段查找
      语法:

      表名__字段

      示例:

      titles = models.Publisher.objects.values_list("book__title")
      

    注意:

     

    操作方面
    操作方面

     

     

    类方面
    类方面

     

    ManyToManyField

    class RelatedManager

    "关联管理器"是在一对多或者多对多的关联上下文中使用的管理器。

    它存在于下面两种情况:

    1. 外键关系的反向查询
    2. 多对多关联关系

    简单来说就是当 点后面的对象 可能存在多个的时候就可以使用以下的方法。

    方法

    create()

    创建一个新的对象,保存对象,并将它添加到关联对象集之中,返回新创建的对象。

    # step1:在book表中创建了一本新书,step2:在作者和书的关系表中添加关联记录
    author_obj.books.create(title="跟金老板学开坦克", publisher_id=2)
    

    add()

    把指定的model对象添加到关联对象集中。
    添加对象

    book_obj = models.Book.objects.get(id=7)
    author_obj.books.add(book_obj)
    

    添加对象列表

    book_objs = models.Book.objects.filter(id__gt=9)
    author_obj.books.add(*book_objs)    # 要把列表打散再传进去
    

    添加id

    author_obj.books.add(12)
    

    set()

    更新model对象的关联对象。

    book_obj = models.Book.objects.first()
    book_obj.authors.set([2, 3])
    

    remove()

    从关联对象集中移除执行的model对象

    book_obj = models.Book.objects.first()
    book_obj.authors.remove(3)
    

    clear()

    从关联对象集中移除一切对象。

    book_obj = models.Book.objects.first()
    book_obj.authors.clear()
    

    注意:

    1. 对于ForeignKey对象,clear()和remove()方法仅在null=True时存在。
    2. 对于所有类型的关联字段,add()、create()、remove()和clear(),set()都会马上更新数据库。换句话说,在关联的任何一端,都不需要再调用save()方法

    聚合查询和分组查询

    聚合

    aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。

    用到的内置函数:

    from django.db.models import Avg, Sum, Max, Min, Count
    

    键的名称是聚合值的标识符,值是计算出来的聚合值。
    1. 键的名称是按照字段和聚合函数的名称自动生成出来的。[字段名__函数名]

    models.Book.objects.all().aggregate(Avg("price"))
    

    键的名称:price__avg

    2. 如果你想要为聚合值指定一个名称,可以向聚合子句提供它。

    models.Book.objects.all().aggregate(avg_price=Avg("price"))
    

    键的名称:avg_price

    3. 如果你希望生成不止一个聚合,你可以向aggregate()子句中添加另一个参数。

    如果你也想知道所有图书价格的最大值和最小值,可以这样查询:

    models.Book.objects.all().aggregate(Avg("price"), Max("price"), Min("price"))
    

    分组

    假设现在有一张公司职员表:

     


     

     

    按照部分分组求平均工资

    1. 原生SQL语句
      select dept,AVG(salary) from employee group by dept;
      
    2. ORM
      from django.db.models import Avg
      Employee.objects.values("dept").annotate(avg=Avg("salary").values(dept, "avg")
      

    连表查询的分组

    1. 原生SQL语句
      select dept.name,AVG(salary) from employee inner join dept on (employee.dept_id=dept.id) group by dept_id;
      
    2. ORM
      from django.db.models import Avg
      models.Dept.objects.annotate(avg=Avg("employee__salary")).values("name", "avg")
      

    更多示例

    1. 查询每一本书的作者个数
    ret = models.Book.objects.all().annotate(author_num=Count("author"))
    print(ret.author_num) # ret是列表,不能对其使用.属性
    for book in ret:
       print("书名:{},作者数量:{}".format(book.title, book.author_num))
    
    1. 查询作者数量大于一的书
    ret=models.Book.objects.all().annotate(author_num=Count("author")).filter(author_num__gt=1)
        print(ret[0].title)
    
    1. 查询各个作者出的书的总价格
    ret=models.Author.objects.all().annotate(price_num=Sum("books__price")).values_list("name", "price_num")
    ret=models.Author.objects.all().annotate(price_num=Sum("books__price")).values("name", "price_num")
    print(ret.values_list("id", "name", "price_num"))
    print(ret)
    for i in ret:
        print(i.get("name"), i.get("price_num"))
    

    F查询和Q查询

    F查询

    Django 提供 F() 对两个字段的值做比较。F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。

    示例

    1. 查询库存数大于卖出数的所有书(两个字段作比较)
    from django.db.models import F
    ret = models.Book.objects.filter(kucun__gt=F("maichu"))
    for book in ret:
        print(book.title, book.kucun, book.maichu)
    
    1. 刷单 把每一本书的卖出数都乘以3
    # 单个对象操作用save
    # obj = models.Book.objects.first()
    # obj.maichu = 100 * 3
    # obj.save()
    
    # 具体的对象没有 update(), QuerySet 对象才有 update() 方法
    models.Book.objects.update(maichu=(F("maichu")+1)*3)
    
    1. 给每一本书的书名后面加上 第一版
    from django.db.models.functions import Concat
    from django.db.models import Value
    
    models.Book.objects.update(title=Concat(F("title"), Value("第一版")))
    

    Q查询

    filter() 等方法中的关键字参数查询都是一起进行 “AND” 的。 如果你需要执行更复杂的查询(例如 OR 语句),你可以使用 Q 对象。

    from django.db.models import Q
    # 查询 卖出数大于1000,并且 价格小于100的所有书
    ret = models.Book.objects.filter(maichu__gt=1000, price__lt=100)
    print(ret)
    # 查询 卖出数大于1000,或者 价格小于100的所有书
    ret = models.Book.objects.filter(Q(maichu__gt=1000) | Q(price__lt=100))
    

    可以组合 & 和 | 操作符以及使用括号进行分组来编写任意复杂的 Q 对象。同时,Q 对象可以使用 ~ 操作符取反,这允许组合正常的查询和取反 (NOT) 查询。

    查询函数可以混合使用 Q 对象和关键字参数。所有提供给查询函数的参数(关键字参数或 Q 对象)都将 "AND" 在一起。但是,如果出现 Q 对象,它必须位于所有关键字参数的前面。

    # Q查询和字段查询同时存在时, 字段查询要放在Q查询的后面
    ret = models.Book.objects.filter(Q(maichu__gt=1000) | Q(price__lt=100), title__contains="金老板")
    print(ret)
    

    事务

    原子性操作: 中间一旦某个环节出了问题,则整个操作都将取消,包括出错环节之前已经执行过的环节。

    try:
        from django.db import transaction
        with transaction.atomic():
            new_publisher = models.Publisher.objects.create(name="火星出版社")
            models.Book.objects.create(title="橘子物语", publish_date=datetime.date.today(), publisher_id=10)  # 指定一个不存在的出版社id
    except Exception as e:
        print(str(e))
    

    参考:https://www.cnblogs.com/liwenzhou/p/8660826.html

  • 相关阅读:
    Android 百度地图开发(一)--- 申请API Key和在项目中显示百度地图
    Session,Cookie,jsessionid,Url重写
    PHP输出当前进程所有变量 / 常量 / 模块 / 函数 / 类
    table自适应宽度
    python学习笔记1(字符串操作)
    jquery-select选中
    dos命令大全
    dos命令之创建文件,文件夹
    PHP中逻辑运算符的高效用法---&&和||
    apache vhost
  • 原文地址:https://www.cnblogs.com/banshaohuan/p/9453577.html
Copyright © 2011-2022 走看看