zoukankan      html  css  js  c++  java
  • Django多表查询

    字段关系

    外键类型在ORM中用来表示外键关联关系,一般把ForeignKey字段设置在 '一对多'中'多'的一方。

    ForeignKey可以和其他表做关联关系同时也可以和自身做关联关系。

    关键字 意义
    to 设置要关联的表
    to_field 设置要关联的表的字段,默认不写关联的是主键
    on_delete 当删除关联表中的数据时,当前表与其关联的行的行为。删除关联数据,与之关联也删除
    db_constraint 是否在数据库中创建外键约束,默认为True。
    models.DO_NOTHING
    删除关联数据,引发错误IntegrityError    
        
    models.PROTECT
    删除关联数据,引发错误ProtectedError
    
    models.SET_NULL
    删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)
    
    models.SET_DEFAULT
    删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)
    
    models.SET
    
    删除关联数据,
    a. 与之关联的值设置为指定值,设置:models.SET(值)
    b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)
    
    

    OneToOneField

    一对一字段。

    通常一对一字段用来扩展已有字段。(通俗的说就是一个人的所有信息不是放在一张表里面的,简单的信息一张表,隐私的信息另一张表,之间通过一对一外键关联)

    关键字 意义
    to 设置要关联的表
    to_field 设置要关联的表的字段,默认不写关联的是主键
    on_delete 当删除关联表中的数据时,当前表与其关联的行的行为。删除关联数据,与之关联也删除

    ManyToManyField

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

    它存在于下面两种情况:

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

    简单来说就是在多对多表关系并且这一张多对多的关系表是有Django自动帮你建的情况下,下面的方法才可使用。

    方法

    create()

    创建一个关联对象,并自动写入数据库,且在第三张双方的关联表中自动新建上双方对应关系。

    models.Author.objects.first().book_set.create(title="偷塔秘籍")
    上面这一句干了哪些事儿:
    1.由作者表中的一个对象跨到书籍比表
    2.新增名为偷塔秘籍的书籍并保存
    3.到作者与书籍的第三张表中新增两者之间的多对多关系并保存
    

    add()

    把指定的model对象添加到第三张关联表中。

    添加对象

    >>> author_objs = models.Author.objects.filter(id__lt=3)
    >>> models.Book.objects.first().authors.add(*author_objs)
    

    添加id

    >>> models.Book.objects.first().authors.add(*[1, 2])
    

    set()

    更新某个对象在第三张表中的关联对象。不同于上面的add是添加,set相当于重置

    >>> 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()
    

    注意:

    对于ForeignKey对象,clear()和remove()方法仅在null=True时存在。

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

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

    用到的内置函数:

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

    示例:

    >>> from django.db.models import Avg, Sum, Max, Min, Count
    >>> models.Book.objects.all().aggregate(Avg("price"))
    {'price__avg': 13.233333}
    

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

    >>> models.Book.objects.aggregate(average_price=Avg('price'))
    {'average_price': 13.233333}
    

    如果你希望生成不止一个聚合,你可以向aggregate()子句中添加另一个参数。所以,如果你也想知道所有图书价格的最大值和最小值,可以这样查询:

    >>> models.Book.objects.all().aggregate(Avg("price"), Max("price"), Min("price"))
    {'price__avg': 13.233333, 'price__max': Decimal('19.90'), 'price__min': Decimal('9.90')}
    

    11|2****分组

    我们在这里先复习一下SQL语句的分组。

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

    img

    我们使用原生SQL语句,按照部分分组求平均工资:

    select dept,AVG(salary) from employee group by dept;
    

    ORM查询:

    from django.db.models import Avg
    Employee.objects.values("dept").annotate(avg=Avg("salary").values(dept, "avg")
    这里需要注意的是annotate分组依据就是他前面的值,
    如果前面没有特点的字段,则默认按照ID分组,
    这里有dept字段,所以按照dept字段分组
    

    连表查询的分组:

    img

    SQL查询:

    select dept.name,AVG(salary) from employee inner join dept on (employee.dept_id=dept.id) group by dept_id;
    

    ORM查询:

    from django.db.models import Avg
    models.Dept.objects.annotate(avg=Avg("employee__salary")).values("name", "avg")
    

    F查询

    我们构造的过滤器都只是将字段值与某个常量做比较。如果我们要对两个字段的值做比较,那该怎么做呢?

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

    # 查询评论数大于收藏数的书籍
     from django.db.models import F
     Book.objects.filter(commnetNum__lt=F('keepNum'))
    
    

    字符串的拼接

       from django.db.models.functions import Concat
       from django.db.models import Value
       models.Product.objects.update(name=Concat(F('name'),Value('爆款')))
    

    Django 支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操作。

    # 查询评论数大于收藏数2倍的书籍
    Book.objects.filter(commnetNum__lt=F('keepNum')*2)
    

    修改操作也可以使用F函数,比如将每一本书的价格提高30元:

    Book.objects.all().update(price=F("price")+30) 
    

    Q查询

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

    from django.db.models import Q
    Q(title__startswith='Py')
    

    Q 对象可以使用&| 操作符组合起来。当一个操作符在两个Q 对象上使用时,它产生一个新的Q 对象。

    bookList=Book.objects.filter(Q(authors__name="yuan")|Q(authors__name="egon"))
    

    等同于下面的SQL WHERE 子句:

    WHERE name ="yuan" OR name ="egon"
    

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

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

    bookList=Book.objects.filter(Q(publishDate__year=2016) | Q(publishDate__year=2017), title__icontains="python")
    

    Q 查询改变默认的查询方式为或

    from django.db.models import F, Q
    q = Q()
    q.connector = 'or'  # 通过这个参数可以将Q对象默认的and关系变成or
    q.children.append(('price',188.88))
    q.children.append(('name','高跟鞋爆款'))
    res = models.Product.objects.filter(q)  # Q对象查询默认也是and
    print(res)
    

    bulk_create批量插入数据

    要求:一次性插入多条数据

    data = ["".join([str(random.randint(65, 99)) for i in range(4)]) for j in range(100)]
    obj_list = [models.A(name=i) for i in data]
    models.A.objects.bulk_create(obj_list)
    

    事务支持

    事务的定义:将多个sql语句操作变成原子性操作,要么同时成功,有一个失败则里面回滚到原来的状态,保证数据的完整性和一致性(NoSQL数据库对于事务则是部分支持)

    # 如果你是买家,你买了一件商品,那么在后台数据库中要做什么操作?
    # 1. 创建一条订单数据
    # 2. 去产品表 将卖出数+1, 库存数-1
    from django.db.models import F
    from django.db import transaction
    # 开启事务处理
    try:
        with transaction.atomic():
            # 创建一条订单数据
            models.Order.objects.create(num="110110111", product_id=1, count=1)
            # 能执行成功
            models.Product.objects.filter(id=1).update(kucun=F("kucun")-1, maichu=F("maichu")+1)
    except Exception as e:
        print(e)
    

    Defer和Only

    defer('id','name'):取出对象,字段除了id和name都有
    only('id','name'):取的对象,只有id和name
    如果点,依然能点出其它列,但是不要点了,因为取没有的列,会再次查询数据库

        ret=models.Author.objects.only('nid')
        for i in ret:
            # 查询不在的字段,会再次查询数据库,造成数据库压力大
            print(i.nam
    

    支持原生的SQL语句

    from django.db import connection, connections
    
    cursor = connection.cursor() # connection=default数据
    cursor = connections['db2'].cursor()
    
    cursor.execute("""SELECT * from auth_user where id = %s""", [1])
    
    row = cursor.fetchone()
    row = cursor.fetchall()
    
    ret=models.Author.objects.raw('select * from app01_author where nid>1')
        print(ret)
        for i in ret:
            print(i)
        print(ret.query)
        # 会把book的字段放到author对象中
        ret=models.Author.objects.raw('select * from app01_book where nid>1')
        print(ret)
        for i in ret:
            print(i.price)
            print(type(i))
    

    自定义Char类型

    from django.db import models
    
    # Create your models here.
    class MyCharField(models.Field):
        def __init__(self,max_length,*args,**kwargs):
            self.max_length = max_length
            super().__init__(max_length=max_length,*args,**kwargs)
    
        def db_type(self, connection):
            return 'char(%s)'%self.max_length
    

    Choice 字段

    models.py

    choices = ((1,‘男’),(2,'女'))
    gender = modles.IntegerField(choices = choices,default = 2 )
    
    res = models.Product.objects.filter(id=1).first()
    print(res.gender) //到到的是数字
    print(res.get_gender_display())  # 获取编号对应的中文注释
    # models.Product.objects.create(...gender=1) // 会对应的存到数据库里面
  • 相关阅读:
    java poi 从服务器下载模板写入数据再导出
    一个华为面试题
    ForEach 循环
    fmt标签格式化数字和时间
    Ichars制作数据统计图
    jQuery中的事件
    oracle学习第四天
    GET请求和POST请求
    Jsp的九个隐含对象
    Oracle学习【语句查询】
  • 原文地址:https://www.cnblogs.com/ruhai/p/11020241.html
Copyright © 2011-2022 走看看