django之 模型层

目录

  • 模型层

模型层

auto_now: 每次修该数据时候,自动将最新的更新时间记录下来

auto_now_add:在创建数据时候将创建时间自动记录下来,之后不会再更改

一.如何只单独测试django中的某一个py文件

如何书写测试脚本
在任意一个py文件中书写以下代码

​ 应用下的tests

或者自己新建一个

    import os


        if __name__ == "__main__":
            os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day53.settings")
            import django
            django.setup()
二.知必会16条

​ 1.all() queryset对象
​ 2.filter() queryset对象
​ 3.get() 数据对象 不推荐使用 条件不存在直接报错
​ 4.create() 返回值是当前创建的数据对象本身
​ 5.update() 更新数据
​ 6.delete() 删除数据
​ 7.first() 取第一个子元素
​ 8.last() 取最后一个子元素
​ 9.values() queryset对象 看似:列表套字典
​ 10.values_list() queryset对象 看似:列表套元组
​ 11.order_by() 排序
​ 12.reverse() 反转
​ 13.exclude() 排除什么什么在外
​ 14.distinct() 去重
​ 15.count() 计数
​ 16.exists() 判断结构是否有数据 返回的是布尔值 了解即可

models.py

rom django.db import models

# Create your models here.

class Movie(models.Model):
    title = models.CharField(max_length=64)
    price = models.DecimalField(max_digits= 8,decimal_places= 2 )
    publish_time = models.DateField()

tests.py

import os
if __name__ == '__main__':
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "new1_8.settings")
    import django
    django.setup()
    from app01 import models
    models.Movie.objects.all()

   # 1.create()
    # models.Movie.objects.create(title='红日', price=122.22, publish_time='2016-4-5')


    # res= models.Movie.objects.create(title='日出东方', price=222.11, publish_time='1998-4-5')
    # #可以直接传日期
    # from datetime import date
    # ctime= date.today()
    # models.Movie.objects.create(title = '西游记',price= 111.11,publish_time= ctime)
    # #2.all()
    # res = models.Movie.objects.all()
    # print(res)
    # #3.fitler()
    # res = models.Movie.objects.filter(id=5)
    # print(res)
    # res= models.Movie.objects.filter(pk=6)#pk就是指代当前的主键自字段名,自动查找非常方便
    # print(res)
    #4.get()#获取的是对象本身,不推荐使用,当查询不存在,直接报错
    # res= models.Movie.objects.get(pk=10)
    # print(res)##西游记
    # print(res.title)
    # print(res.price)
    # res1= models.Movie.objects.filter(pk=1000)
    # print(res1)###查询不存在 直接报错
    #5.value()#获取指定字段对的数据[{},{},{}]
    # res = models.Movie.objects.values('title','price')
    # print(res)
    # print(res.query)
    #6.values_list  获取指定字段对的数据 结果是[(),(),()]
    # res= models.Movie.objects.values_list('title','price')
    # print(res)
    #7.first()  取第一个子元素 title 对象
    # res1 = models.Movie.objects.filter().first()
    # print(res1)  ##d打印的只是第一个对象:日出东方
    # res1 = models.Movie.objects.filter()
    # print(res1)
    #8.last 取最后一个子元素 是对象
    # res = models.Movie.objects.last()
    # print(res)
    #9.update 更新数据  返回值是受影响的行数
    # res= models.Movie.objects.filter(pk=6).update(title = '三国演义')
    # print(res)
    #10 delete 删除数据 返回值 (1, {'app01.Movie': 1})受影响的表及行数
    # res = models.Movie.objects.filter(pk=5).delete()
    # print(res)
    #count() 统计数据的条数
    # res = models.Movie.objects.count()
    # print(res)
    #12.order_by 按照指定字段排序
    # res = models.Movie.objects.order_by('price')
    # print(res)

    #13.exclude() 排除什么之外,少选条件
    # res= models.Movie.objects.exclude(pk=4)
    # print(res)

    #14.exists 返回的布尔值 判断前面的对象是否存在
    # res= models.Movie.objects.filter(pk=1000).exists()
    # print(res)
    #15.reverse()反转
    # res= models.Movie.objects.order_by('price').reverse()
    # print(res)
    #16 .distinct()去重 前提是 必须是完全一样的数据
    # res= models.Movie.objects.values('title','price').distinct()
    # print(res)   
三. 神奇的双下划线查询

神奇的双下划线查询

                大于:__gt
                小于:__lt
                大于等于:__gte
            小于等于:   __lte
            范围内:    __in
                __range  顾头也顾尾
            模糊查询
                __contains   区分大小写
                __icontains  忽略大小写
            年月日
                create_time__year
                create_time__month  

models.py

注意:下面所有的事例,用的都是这个的models orm

class Book(models.Model):
    title = models.CharField(max_length= 32)
    price = models.DecimalField(max_digits=8,decimal_places = 2)
    publish_time = models.DateField(auto_now_add = True)

#出版社 一对多 、
    publish = models.ForeignKey(to='Publish')
    #作者 多对多
    authors = models.ManyToManyField(to='Author')
    def __str__(self):
        return self.title  ##print(obj) 可以触发这个方法 得到返回值

    #库存数
    stock = models.BigIntegerField(default= 1000)
    #卖出数
    sale_out = models.BigIntegerField(default = 1000)



class Publish(models.Model):
    name = models.CharField(max_length = 32)
    addr = models.CharField(max_length=64)

    # def __str__(self):
    #     return self.name  ##print(obj) 可以触发这个方法 得到返回值

class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()

    #作者详情表 一对一
    author_detail = models.OneToOneField(to = 'AuthorDetail')

class AuthorDetail(models.Model):
    phone = models.BigIntegerField()
    addr = models.CharField(max_length=32)

tests.py

   #1.查询价格大于200 的电影
    # res= models.Movie.objects.filter(price__gt=200)
    # print(res)
    #2.查询价格小于500的电影
    # res= models.Movie.objects.filter(price__lt=500)
    # print(res)
    #3.查询价格大于等于122.11的电影
    # res = models.Movie.objects.filter(price__gte=122.11)
    # print(res)
    #4查询价格小于等于190.11的电影
    # res= models.Movie.objects.filter(price__lte=190.11)
    #     # print(res)
    #查询价格是190.11 或者 122.11 的电影
    # res= models.Movie.objects.filter(price__in=[190.11,122.11])
    # print(res)
    # 6.查询价格在200到900之间的电影  顾头也顾尾
    # res = models.Movie.objects.filter(price__range=(200,900))
    # print(res)
    # 7.查询电影名中包含字母p的电影
    """
    模糊查询:
        关键字 like
        关键符号
            %
            _
    """
    # res = models.Movie.objects.filter(title__contains= 'p') #默认是区分大小    写的
    # print(res)
    # res= models.Movie.objects.filter(title__icontains='p')#i忽略大小写      ignore
    # print(res)
    #查询201年的出版的电影
    # res = models.Movie.objects.filter(publish_time__year=2014)
    # print(res)
    # #查询1月份出版的电影
    # res = models.Movie.objects.filter(publish_time__month=1)
    # print(res)
五.外键字段的增删改查

一对一

如下图的事例:

1.增: create

publish (虚拟字段) 或者 publish_id 2 种

 # publish_id 
    # models.Book.objects.create(title='明朝那些事',price= 223.33,publish_id=2)
    
#publish
    # publish_obj = models.Publish.objects.get(pk=1)#得到的是一个出版社的对象,不是queryset对象
    # print(publish_obj)## 东方出版社
    # models.Book.objects.create(title='心理学',price=222.12,publish=publish_obj)
    #上面的这个publish是一个虚拟的字段,后面的publish_obj 会被前面的publish自动匹配到主键值,并且获取结果

2.改:update

    # models.Book.objects.filter(pk=1).update(publish_id = 3)#这种的是直接再上面进行修改
    # models.Book.objects.filter(pk=1).update(title= '文明古国')#这种的是直接再上面进行修改
    # publish_obj= models.Publish.objects.get(pk=4)
    # models.Book.objects.filter(pk=3).update(publish=publish_obj)

3.删 :delete

4.查:filter

注意:外键字段再1.x版本中默认的就是级联删除,2.x版本 则需要你自己手动指定删除

多对多

操作第三张关系表 orm提供的简便方法 自己手动去操作第三张表

book_obj.authors.add()

book_obj.authors.remove()

book_obj.authors.set()

​ 上面三个方法括号内即可以传数字也可以传对象并且都支持传多个
​ 但是set方法括号内必须是一个可迭代对象 (你需要将数据或对象用小括号或中括号)
​ clear()括号内不需要传任何参数 是直接清空第三张关系表中对象数据

#1.给书籍绑定作者关系
    # book_obj = models.Book.objects.filter(pk=1).first()
    # print(type(book_obj))##
    # print(book_obj) #文明古国
    #如果不加.first() 则拿到的是一个queryset的对象,是一个列表,
    #我们需要的是书的对象

    #书和作者是第三张表决定的,意味者需要操作第三张表
    # print(book_obj.authors)#书籍对象点虚拟字段authors 就类似于已经跨到了书籍和作者的第三张关系表中
    #上面的答应你结果是app01.Author.None  没有错
    # book_obj.authors.add(1)
    # book_obj.authors.add(2,3)#已经八关系添加到数据库中

    # author_obj= models.Author.objects.get(pk=1)
    #得到的是一个作者的对象
    # author_obj1 = models.Author.objects.get(pk=3)
    # book_obj.authors.add(author_obj)
    # book_obj.authors.add(author_obj,author_obj1)
    '''
    add是专门给第三张表关系表添加数据
    括号内可以传数字 也可以是传对象,并且都是支持传多个
    '''
    #2.移除书籍和作者的绑定关系 remove
    # book_obj = models.Book.objects.filter(pk=1).first()
    # book_obj.authors.remove(1) #对象点虚拟的字段 就会直接跳到这个第三张表

    # author_obj = models.Author.objects.get(pk=2)
    # author_obj1 = models.Author.objects.get(pk=3)
    # book_obj.authors.remove(author_obj,author_obj1)
    '''
    remove 专门给第三张关系表移除数据,括号内的可以传数字也是可以出传对象,并且支持
    传一个或者多个
    '''

    #3.修改书籍和作者之间的关系 set
    # book_obj = models.Book.objects.filter(pk=1).first()
    # book_obj.authors.set([3,])##这个地方放的单个的数字,所以要用元组的形式,不然报错的
    # book_obj.authors.set((2,3,))

    # author_obj = models.Author.objects.get(pk=2)
    # author_obj1 = models.Author.objects.get(pk=3)
    # book_obj.authors.set((author_obj,author_obj1))
    '''
    set修改书籍和作者的关系
    括号内支持传数字和对象,但是需要的是可迭代的对象
    set((3,)) 或者set([3,]) 这样来放置 不然报错
    '''

    #4.清空书籍和作者的关系
    # book_obj = models.Book.objects.filter(pk=3).first()
    # book_obj.authors.clear()#去第三张表中 清除 id=1的书 所有的书籍
    '''
    clear() 清空关系,不需要任何的参数
六.跨表查询的方式

跨表查询的方式

1.子查询将一张表的查询结果 当作另外一张表的查询条件正常解决问题的思路:分步操作

2.链表查询inner join

left joinright

joinunion

在写sql语句的时候,千万不要想着一次性将语句写完,一定要一点查一点 再写一点

正反向的概念:

正向 :

​ 跨表查询的时候,外键字段是否再当前数据对象中,如果在, 查询另外一张关系表,叫正向

反向 :

​ 上述的定义,如果不在,则叫做反向

口诀 :

正向查询按外键字段 反向查询按表名小写_set

1.子查询将一张表的查询结果 当作另外一张表的查询条件正常解决问题的思路:分步操作

#基于对象的跨表查询(子查询)
    #1.查询书籍pk为1的出版社名称
    # book_obj = models.Book.objects.filter(pk=1).first()
    # print(book_obj.publish)#正向的查询外键字段
    # print(book_obj.publish.name)
    # print(book_obj.publish.addr)

    #2 查询书籍为pk为9的所有作者的姓名
    # book_obj = models.Book.objects.filter(pk=9).first()
    # # print(book_obj.authors)#app01.Author.None  需要用取全部的
    # print(book_obj.authors.all())
    # author_list = book_obj.authors.all()#, ]>
    # for author_obj in author_list:
    #     print(author_obj.name)

    #3.查询作者pk为1的电话号码
    # author_obj= models.Author.objects.filter(pk=1).first()
    # print(author_obj.author_detail)
    # print(author_obj.author_detail.phone)
    # print(author_obj.author_detail.addr)
    '''
    正向查询的时候,当外键字段对应的数据可以有多个时候,需要加.all()
    否则 如果没有多个的话,点外键字段即可获得对应的数据对象
    '''
    #4.查询出版社名称为东方出版社出版过的书籍
    # publish_obj = models.Publish.objects.filter(name= '东方出版社').first()
    # print(publish_obj.book_set)#app01.Book.None
    # print(publish_obj.book_set.all())

    #5.查询作者jasn写过的书
    # author_obj = models.Author.objects.filter(name= 'jason').first()
    # print(author_obj.book_set.all())

    #6.查询手机号为120的作者姓名
    # author_detail_obj = models.AuthorDetail.objects.filter(phone ='120').first()
    # print(author_detail_obj.author.name)
    # print(author_detail_obj.author.age)

    ''''
    基于反向对象的反向查询,表名小写是否需要加上_set.all() 
    一对多和多对多的时候需要加上
    一对一不需要
    '''

2. 基于双下划线跨表查询(链表查询)

 #1.查询书籍pk为1的出版社名称
    # book_obj = models.Book.objects.filter(pk=1).first()
    # print(book_obj.publish.name)
    #正向
    # res = models.Book.objects.filter(pk=1).values('publish__name')
    # #写外键字段就代表已经到了外键字段管理的那张表哪里了
    # print(res)
    #反向
    # res= models.Publish.objects.filter(book__pk=1).values('name')#拿出版社pk为1的书籍对应的出版社
    # print(res)

    #2.c查询书籍pk为3的作者姓名和年龄
    #正向
    # res = models.Book.objects.filter(pk=3).values('title','authors__name','authors__age')
    # print(res)
    #反向
    # res = models.Author.objects.filter(book__pk=3).values('name','age','book__title')
    # print(res)

    #3.查询作者是jason的年龄和手机号码
    #正向
    # res= models.Author.objects.filter(name='jason').values('age','author_detail__phone')
    # print(res)

    #反向
    # res = models.AuthorDetail.objects.filter(author__name='jason').values('phone','author__age')
    #     # print(res)

    #4.查询书籍的pk为8的作者的手机号
    #正向
    # res = models.Book.objects.filter(pk=8).values('authors__author_detail__phone')##双下划线可以一直去跨
    # print(res)
    #反向
    # res = models.AuthorDetail.objects.filter(author__book__pk=1).values('phone')
    # print(res)
    '''
    只要表之间有关系,就可以通过正向的外键字段或者反向的表名小写 连续的跨表使用
    '''
七. 聚合查询

关键字
aggregate
模块导入
from django.db.models import Max,Min,Sum,Count,Avg

from django.db.models import Max, Min, Avg,Count,Sum
    #查询所有书的平均价格
    # res = models.Book.objects.aggregate(avg_num = Avg('price'))
    # print(res)
    #查询最贵的书
    # res = models.Book.objects.aggregate(max_num = Max('price'))
    # print(res)
    #全部使用一遍
    # res = models.Book.objects.aggregate(Avg('price'),Max('price'),Min('price'),Count('pk'),Sum('price'))
    # print(res)
八. 分组查询
        关键字
            annotate
        模块导入
            from django.db.models import Max,Min,Sum,Count,Avg
#1.统计每一本书的作者个数
    # res= models.Book.objects.annotate(author_num= Count('authors')).values('title','author_num')
    # print(res)##查询作者表 这个要跨到作者表
    #2.统计每个出版社卖的最便宜的书的价格
    # res= models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price','book__title')
    # print(res)

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

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

    #5.按照表中的某一个指定字段分组
    # res = models.Book.objects.values('price').annotate()#是用价格分组
九. F和Q查询

模块导入
from django.db.models import F,Q
F查询
能够帮我们获取到表中指定字段对应的值

1.查询库存数大于卖出数的书籍
    # res = models.Book.objects.filter(stock__gt=F('sale_out'))
    # print(res)
    #2.将所有书的价格提高100元
    # res = models.Book.objects.update(price=F('price') +100)
    # print(res)

Q查询
能够修改查询条件的关系 and or not
filter括号内多个条件逗号隔开 是and关系

and :,

or :|

not:~

#1. 查询书的名字是文明古国 或者价格是300的书
    # res = models.Book.objects.filter(Q(title='python入门'),Q(price=1000))  # 逗号是and关系
    # res= models.Book.objects.filter(Q(title='文明古国')|Q(price = 300.00))
    # print(res)
    # res = models.Book.objects.filter(~Q(title='文明古国')|Q(price=300))
    # print(res)
十.Q的高阶用法
# res = models.Book.objects.filter('title'='python入门')
    q = Q()
    q.connector = 'or'#q对象的默认的也是and的关系,可以通过connector来改变
    q.children.append(('title','文明古国'))
    q.children.append(('price',300))

    res = models.Book.objects.filter(q)
    print(res)##, ]>

你可能感兴趣的:(django之 模型层)