CSIC_716_2020108【Django入门---模型层】

 

时间格式的字段

publish_time = models.DateField() # 年月日

publish_time = models.DateTimeField() # 年月日 时分秒

publish_time = models.DateField()  # 年月日
publish_time = models.DateTimeField()  # 年月日 时分秒
    """
    auto_now:每次修改数据的时候 都会自动将最新的更新时间记录下来
    auto_now_add:只在创建数据的时候将创建时间自动记录下来 之后不会自动改变
    """

用法示例
publish_time = models.DateField(auto_now=True)  
publish_time = models.DateTimeField(auto_now_add=True)  

  

单表查询

queryset对象可以通过 queryset对象.query 可以查看orm语句对应的sql语句

也可以在django的settings配置文件中加入以下配置,即可查看所有orm操作对应的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',
        },
    }
}
Django终端打印SQL语句
 必知必会16条
        1.create()  返回值:对象本身
        2.all()     返回值:queryset对象
        3.filter()  返回值:queryset对象
        4.update()   返回值:影响的行数
        5.delete()   返回值:影响的行数
        6.first()   返回值:queryset结果中的对象
        7.last()    返回值:queryset结果中的对象
        8.get()    返回值:对象本身,如果get的对象不存在,就报错
        9.values('field')   返回值:queryset对象,对象中包着{field:value}字典
        10.values_list('field')  返回值:queryset对象,对象中包着(value,)元组
        11.order_by()  返回值:queryset对象; order_by('name')升序;和order_by('-name')降序
        12.count()    返回值:整型,统计queryset中元素的数量
        13.exclude()   返回值:queryset对象
        14.exists()     返回值:布尔型, 用于判断能否根据条件查出queryset对象
        15.reverse()   返回值:queryset对象 ,order_by('name').reverse()等价于order_by('-name')
        16.distinct()  返回值:queryset对象, 去重务必要保证value()中所列的字段完全一致,才能去重

  

双下划线查询

****************大于(等于)*******
__gt=
__lt=
__gte=  # greater than equal
__lte=

****************范围*******
__in=[ ,,,]
__range=( ,)  #包含边界

***************模糊查询*******
__contains=‘F’     #严格大小写
__icontains=‘F’    #忽略大小写   ignorecontains

  

  

****************对于时间格式的字段****************

fieldname__year=2020  #查询年份是2020的记录
fieldname__month=12  #查询月份是12的记录

  

 当表中有外键的时候,通过ORM增删改查的方法

 这里要知道一个前提条件,外键字段在模型类中如果叫field,到数据库中会自动加一个尾缀_id变成field_id

 在多对多的表关系中,外键虽然建在使用频率较高的表上,但是数据库中,使用频率较高的表中没有外键字段,外键字段实际是出现在多对多生成的第三张表中。

故在初始化使用频率较高的那张表时,不需要输入多对多外键的值,多对多外键值及其绑定关系需要单独在第三张表中建立。

模型类中定义的表的操作 

字段以数据库中的为准   进行新增(多对多外键字段不在此新增)

#操作数据库对应的字段,一句话直接创建,此时字段以数据库中的为准
models.Book.objects.create(title='鬼谷子',press_id=4,book_detail_id=2)

 

以模型类中的字段名为准  进行新增(多对多外键字段不在此新增)

#先获取对象(两种方式获取对象)
press_obj = models.Company.objects.filter(pk=3).first()  # 一定要从queryset中通过例如 .first()取到对象
press_obj = models.Company.objects.get(pk=2)  # 或者通过get直接取到对象
book_detail_obj = models.BookDetail.objects.filter(pk=1).last()
外键直接等于对象即可,此时的外键不用加尾缀_id,以模型类中的字段名为准
res1 = models.Book.objects.create(title='诗经', press=press_obj, book_detail=book_detail_obj) 

 查用filter、改用update,方法与上面增类似,也有两种方式。

 

多对多的情况下衍生出的第三张表的增删改查

 增

方式一

author_obj1 = models.Author.objects.get(pk=1)  #取出外键关联的对象
author_obj2 = models.Author.objects.get(pk=2)  #取出外键关联的对象

book_obj = models.Book.objects.get(pk=1) # 取出外键所在的对象

book_obj.author.add(author_obj1, author_obj2)   #建立绑定关系

方式二

book_obj = models.Book.objects.get(pk=2)
book_obj.author.add(3, 4)  # 直接与作者的id建立绑定关系

  

add专门给第三张关系表添加数据,括号内即可以传数字也可以传对象 并且都支持传多个

移除绑定关系用remove( , )

更新绑定关系用set(   ) 括号内一定要构造成可迭代对象(列表或元组)

清除某个对象外键的绑定关系用 .clear(  )  ,括号内不需要任何参数

多(跨)表查询

跨表查询的方式
1.子查询 将一张表的查询结果当做另外一张表的查询条件
正常解决问题的思路 分步操作
2.链表查询
inner join
left join
right join
union
建议:在写sql语句或者orm语句的时候 千万不要想着一次性将语句写完 一定要写一点查一点再写一点

正向查询反向查询的概念:

正向查询:跨表查询的时候,当外键在当前对象中,去查另一个表的数据时,就是正向查询,正向查询用字段名

反向查询:跨表查询时,当外键在需要查询的表中时,就是反向查询,反向查询用表名小写

反向查询时,需要以_set.all()结尾,因为会查到多个结果。

例如图书与出版社是一对多的关系,即一种图书只能是一个出版社,而一家出版社可以对应多种图书。

基于对象的跨表查询(正向查询):【子查询】

先获取对象,在通过外键的字段名,直接以句点符得到外键所在的对象,如果对象可能会有多个的话,要在对象结尾加上 .all()

基于对象的跨表查询(反向查询):【子查询】

如果是一对多或者多对多关系,先获取对象,通过外键所在的表名,通过    对象.小写表名_set.all( ) 即可查到结果。

如果是一对一关系,那么先获取对象,然后   对象.小写表名   就可以查到结果

 基于双下划线的跨表查询:【链表查询】(非常重要

models.Book.objects.filter(pk=1).values('publish__name') 正向查询
models.Publish.objects.filter(book__pk=1).values('name') 反向查询
__也可以连续跨越多张表,再通过__取值
查到的结果是queryset,即 [{'':''},{'':''}]
只要表之间有关系 ,就可以通过正向的外键字段或者反向的表名小写 连续跨表操作。

    # 基于双下划线跨表查询(链表查询)
    # 1.查询书籍pk为1的出版社名称
    # models.Book.objects.filter(pk=1).values('publish__name')
    # models.Publish.objects.filter(book__pk=1).values('name')
    # 正向
    # res = models.Book.objects.filter(pk=1).values('publish__name')  # 写外键字段 就意味着你已经在外键字段管理的那张表中
    # print(res)
    # 反向
    # res = models.Publish.objects.filter(book__pk=1)  # 拿出版过pk为1的书籍对应的出版社
    # res = models.Publish.objects.filter(book__pk=1).values('name')
    # print(res)


    # 2.查询书籍pk为1的作者姓名和年龄
    # res = models.Author.objects.filter(book__pk=1).values(name,author_detail__age)
    # res = models.Book.objects.filter(pk=1).values(author__age,author__author_detail__age)

    # 正向
    # res = models.Book.objects.filter(pk=1).values('title','authors__name','authors__age')
    # print(res)
    # 反向
    # res = models.Author.objects.filter(book__pk=1)  # 拿出出版过书籍pk为1的作者
    # res = models.Author.objects.filter(book__pk=1).values('name','age','book__title')
    # print(res)

    # 3.查询作者是jason的年龄和手机号
    #
    # models.Author.objects.filter(name='jason').values(age,detail__phone)
    # (models.Author_detail.objects.filter(author__name=jason).values(author__age, phone)

    # 正向
    # res = models.Author.objects.filter(name='jason').values('age','author_detail__phone')
    # print(res)
    # 反向
    # res = models.AuthorDetail.objects.filter(author__name='jason')  # 拿到jason的个人详情
    # res = models.AuthorDetail.objects.filter(author__name='jason').values('phone','author__age')
    # print(res)

    # 查询书籍pk为的1的作者的手机号

    # res = models.Book.objects.filter(pk=1).values('authors__author_detail__phone')
    # print(res)

    # res = models.AuthorDetail.objects.filter(author__book__pk=1).values('phone')
    # print(res)

    """
    只要表之间有关系  你就可以通过正向的外键字段或者反向的表名小写 连续跨表操作
    """
重点理解

(务必掌握折叠的代码)

聚合查询

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

aggregate ( 聚合函数要给他起个名字 = 关键字(‘fieldname’),支持多个  )

res = models.Book.objects.aggregate(avg_num=Avg('price'))

分组查询

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

annotate ( 聚合函数要给他起个名字 = 关键字(‘fieldname’)  )

分组的总结:  首先明确分组的依据是哪一个类模型,其次通过双下划线查询,结合聚合函数,加上filter筛选和values取值,查出结果。

1.统计每一本书的作者个数
res=models.Book.objects.annotate(author_num=Count('authors')).values('title','author_num')

2.统计出每个出版社卖的最便宜的书的价格
res=models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price','book__title')


3.统计不止一个作者的图书
res=models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1).values('title')


4.查询各个作者出的书的总价格
res=models.Author.objects.annotate(price_sum=Sum('book__price')).values('name','price_sum')

 

自定义分组

 5.如何按照表中的某一个指定字段分组
res = models.Book.objects.values('price').annotate()  就是以价格分组

  

F与Q查询

from django.db.models import F , Q

F('fieldname')  获取字段对应的值

models.Book.objects.update(price=F('price') + 100)  # 全体价格+100

models.Book.objects.filter(kucun__gt=F('maichu'))  #筛选库存大于卖出

  

Q能够改变查询的条件关系  and or not

# 名字是python入门and价格是1000的书籍
models.Book.objects.filter(title='python入门',price=1000)

# 名字是python入门and价格是1000的书籍
models.Book.objects.filter(Q(title='python入门'),Q(price=1000))  

# 名字是python入门or价格是1000的书籍
models.Book.objects.filter(Q(title='python入门')|Q(price=1000))  

# 名字(not)不是python入门or价格是1000的书籍
models.Book.objects.filter(~Q(title='python入门')|Q(price=1000))  

  

Q的高级用法

#先构造Q类的对象
q = Q()

#其次定下q对象之间连接时的关系,默认是and,可以按照以下方法调整
q.connector = 'or'

#然后给q对象增加内容
q.children.append(('fieldname1','value1'))  # 括号内的元组都是字符串
q.children.append(('fieldname2','value2'))  # 括号内的元组都是字符串

#写查询语句,筛选条件直接放q
models.Book.objects.filter(q)  #q类似于   fieldname1=‘value1’  or fieldname2=‘value2’

  

原文地址:https://www.cnblogs.com/csic716/p/12168678.html