杨梅冲
每天在想什么呢?

一、单表操作

# 单表查询操作基本方法
class BookList(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8,decimal_places=2) # 总共8位,小数占2位
    publist_date = models.DateField()  # DateField年月日,DateTimeField详细时间

#单独测试models.py文件
# 将manage.py中前4行拷贝到一个新的test.py文件中
import os
import sys

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day20.settings")
    import django
    django.setup()
    from app01 import models
        # 插入语句
    # book_obj = models.BookList.objects.create(title="三国演义",price=1123.22,publist_date='2019-08-28')
    # import datetime
    # ctime = datetime.datetime.today()
    # book_obj = models.BookList.objects.create(title="红楼梦",price=1666.22,publist_date=ctime)
    # print(book_obj)  # BookList object

    # 更新数据
    # models.BookList.objects.filter(title="三国演义").update(price=1123.22)
    # queryset方法都是批量更新操作

    # 查询
    # print(models.BookList.objects.all())  # <QuerySet [<BookList: 三国演义>, <BookList: 红楼梦>]>
    # print(models.BookList.objects.filter(pk=1))  # <QuerySet [<BookList: 三国演义>]>  # 推荐使用
    # # get获取到的就是数据对象本身,但是条件不满足的时候会直接报错,不推荐使用
    # print(models.BookList.objects.get(pk=3))  # 红楼梦

    # 删除
    # models.BookList.objects.filter(pk=1).delete()

    # 更多查询方法
    # exclude取反
    # print(models.BookList.objects.exclude(pk=1))

    # values 拿对应的字段,返回的是列表套字典
    # print(models.BookList.objects.values('title','price'))
    # <QuerySet [{'title': '三国演义', 'price': Decimal('1123.22')}, {'title': '红楼梦', 'price': Decimal('1666.22')}]>

    # value_list 返回的是列表套元组
    # print(models.BookList.objects.values_list('title','price'))
    # <QuerySet [('三国演义', Decimal('1123.22')), ('红楼梦', Decimal('1666.22'))]>

    # order by 查询结果排序 默认升序
    # print(models.BookList.objects.order_by('price'))
    # <QuerySet [<BookList: 三国演义>, <BookList: 红楼梦>]>
    # 降序
    # print(models.BookList.objects.order_by('price').reverse())

    # 去重:去重的前提是:数据必须是完全一样的
    # print(models.BookList.objects.filter(title="三国演义").values('title','price').distinct())
    # <QuerySet [{'title': '三国演义', 'price': Decimal('1123.22')}]>

    # count()
    # print(models.BookList.objects.all().count())

    # first/last
    # print(models.BookList.objects.first())
    # print(models.BookList.objects.last())

    # exists
    # print(models.BookList.objects.filter(pk=2).exists())
# 13个必须会的操作
# 返回QuerySet对象的方法有
all()  查询所有结果
filter()  它包含了与所给筛选条件相匹配的对象
exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象
order_by()
 reverse(): 对查询结果反向排序,请注意reverse()通常只能在具有已定义顺序的QuerySet上调用(在model类的Meta中指定ordering或调用order_by()方法)
distinct(): 从返回结果中剔除重复纪录(如果你查询跨越多个表,可能在计算QuerySet时得到重复的结果。此时可以使用distinct(),注意只有在PostgreSQL中支持按字段去重

# 特殊的QuerySet
values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列
values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列

# 返回具体对象的
get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误
first() : 第一条记录
last() : 最后一条记录

# 返回布尔值的方法有
exists(): 如果QuerySet包含数据,就返回True,否则返回False

# 返回数字的方法有
count(): 返回数据库中匹配查询(QuerySet)的对象数量

二、单表查询之双下划线操作

models.Tb1.objects.filter(id__lte=10, id__gt=1)   # 获取id大于1 且 小于等于10的值
 
models.Tb1.objects.filter(id__in=[11, 22, 33])   # 获取id等于11、22、33的数据
models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in
 
models.Tb1.objects.filter(name__contains="ven")  # 获取name字段包含"ven"的
models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
 
models.Tb1.objects.filter(id__range=[1, 3])      # id范围是1到3的,等价于SQL的bettwen and
 
类似的还有:startswith,istartswith, endswith, iendswith

date字段还可以:
models.Class.objects.filter(datetime__year=2017)
date字段可以通过在其后加__year,__month,__day等来获取date的特点部分数据


# date
        #
        # Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
        # Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))

        # year
        #
        # Entry.objects.filter(pub_date__year=2005)
        # Entry.objects.filter(pub_date__year__gte=2005)

        # month
        #
        # Entry.objects.filter(pub_date__month=12)
        # Entry.objects.filter(pub_date__month__gte=6)

        # day
        #
        # Entry.objects.filter(pub_date__day=3)
        # Entry.objects.filter(pub_date__day__gte=3)

        # week_day
        #
        # Entry.objects.filter(pub_date__week_day=2)
        # Entry.objects.filter(pub_date__week_day__gte=2)
# 需要注意的是在表示一年的时间的时候,我们通常用52周来表示,因为天数是不确定的

三、图书管理系统表设计

表关系
    一对一
    一对多
    多对多
ps:站在两边判断是否可以同时有多个对方 如果都可以 那么就是多对多 如果是单向的一对多 那么就是一对多 如果都不是 要么没有任何关系 要么就是一对一 Book 书籍 Publish 出版社 Author 作者 AuthorDetail 作者详情 书和出版社 就是一个一对多 书和作者 多对多 作者和作者详情 一对一
# models.py 表结构
"""
一对多 :外键字段 通常建在多的一方
多对多 :外键字段 无论建在哪一方都可以,但是推荐建在查询频率较高的表
一对一 :外键字段 无论建在哪一方都可以,但是推荐建在查询频率较高的表
"""
class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.CharField(max_length=32)
    publish_date = models.DateField(auto_now_add=True)
    # 出版社外键
    publish = models.ForeignKey(to='Publish')  # 默认关联的就是Publist表的主键字段
    # 作者外键
    authors = models.ManyToManyField(to='Author') # 默认关联的就是Author表的主键字段
    # 一对多外键字段,在书写的时候,orm会自动加_id后缀
    """多对多字段是虚拟字段,不会在表中展示出来
        只是用来告诉django orm 自动 创建书籍和作者的第三张表
        还可以跨表查询的时候提供方便
    """

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

class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.CharField(max_length=3)
    male = models.CharField(max_length=1)
    # 一对一
    # 一对一外键字段,在书写的时候,orm会自动加_id后缀
    author_detail = models.OneToOneField(to='AuthorDetail')

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

#数据自己伪造就可以
    """ ORM 联表操作 """
    # 外键字段的增
    # models.Book.objects.create(title='三国演义',price='98.5',publish_id=1)
    # models.Book.objects.create(title='红楼梦',price='128.88',publish_id=1)
    # models.Book.objects.create(title='密卷',price='58',publish_id=4)
    # publish_obj = models.Publish.objects.filter(pk=2).first()
    # models.Book.objects.create(title='西游记',price='90',publish=publish_obj)

    #
    # models.Book.objects.filter(pk=1).update(publish_id=3)
    # 虚拟对象直接传字段
    # publish_obj = models.Publish.objects.filter(pk=2).first()
    # models.Book.objects.filter(pk=1).update(publist=publish_obj)

    # 作者和书籍绑定关系
    # book_obj = models.Book.objects.filter(pk=1).first()
    # book_obj.authors.add(1) # 在第三张表book_authors中,添加书籍和作者的关系,也可以添加2条add(1,2),2本书是这个作者写的
    # author_obj1 = models.Author.objects.filter(pk=1).first()
    # author_obj2 = models.Author.objects.filter(pk=2).first()
    # book_obj.authors.add(author_obj1,author_obj2)
    """
    add既支持传数字,也支持传对象,两者也都可以是多个
    """
    #
    # book_obj = models.Book.objects.filter(pk=1).first()
    # book_obj.authors.set([2,])
    """
    set既支持传数字,也支持传对象,两者也都可以是多个
    注意:传入的格式必须是可迭代对象
    """

    #
    # book_obj = models.Book.objects.filter(pk=1).first()
    # book_obj.authors.remove(2)
    """
    remove既支持传数字,也支持传对象,两者都可以是多个
    """
    # 清空
    book_obj = models.Book.objects.filter(pk=1).first()
    book_obj.authors.clear() # 清空当前数据所有的关联信息
    """
    clear()内不需要传任何参数
    """

四、Django终端打印SQL语句

# settings.py文件中,加了这段话后,会将django执行的sql语句都打印出来
        LOGGING = {
            'version': 1,
            'disable_existing_loggers': False,
            'handlers': {
                'console':{
                    'level':'DEBUG',
                    'class':'logging.StreamHandler',
                },
            },
            'loggers': {
                'django.db.backends': {
                    'handlers': ['console'],
                    'propagate': True,
                    'level':'DEBUG',
                },
            }
        }

#  SELECT `app01_book`.`title` FROM `app01_publish` INNER JOIN `app01_book` ON (`app01_publish`.`id` = `app01_book`.`publish_id`) 
WHERE (`app01_publish`.`name` = '南方出版社' AND `app01_book`.`price` > '19') LIMIT 21; args=('南方出版社', '19')

五、ORM多表查询

# 正向与反向的概念解释
        正向查询按字段(字典建表时的关联字段)
        反向查询按表名小写...

# 一对一
# 正向:author---关联字段在author表里--->authordetail        按字段
# 反向:authordetail---关联字段在author表里--->author        按表名小写
            # 查询jason作者的手机号   正向查询
            # 查询地址是 :山东 的作者名字   反向查询

# 一对多
# 正向:book---关联字段在book表里--->publish        按字段
# 反向:publish---关联字段在book表里--->book        按表名小写_set.all() 因为一个出版社对应着多个图书

# 多对多
# 正向:book---关联字段在book表里--->author        按字段
# 反向:author---关联字段在book表里--->book        按表名小写_set.all() 因为一个作者对应着多个图书

5.1 基于对象的跨表查询:子查询

# 基于对象的跨表查询
# 查询书籍id为1的出版社名称(正向)
    # book_obj = models.Book.objects.filter(pk=1).first()
    # print(book_obj.publish)  # Publish object
    # print(book_obj.publish.name) #南方出版社
# 查询南方出版社出版过的书的名字(反向)
    # publish_obj = models.Publish.objects.filter(name="南方出版社").first()
    # print(publish_obj.book_set)  # app01.Book.None 意味着语句没写全,_set说明有多个结果
    # print(publish_obj.book_set.all()) # <QuerySet [<Book: Book object>, <Book: Book object>]>

# 查询作者simon的手机号(正向)
    # author_obj = models.Author.objects.filter(name="simon").first()
    # print(author_obj.author_detail.phone)
# 根据手机号150查作者(反向)
    # authordetail_obj = models.AuthorDetail.objects.filter(phone=150).first()
    # print(authordetail_obj.author.name)

# 反向查询:根据作者simon查询手机号
res1 = models.AuthorDetail.objects.filter(author__name='simon').values('phone')
print(res1)
# 反向查询:查询年龄和手机号
res =models.AuthorDetail.objects.filter(author__name='simon').values('author__age','phone')
# 多对多
# 查询书籍ID为1的作者姓名
    # book_obj = models.Book.objects.filter(pk=1).first()
    # print(book_obj.authors.all()) # <QuerySet [<Author: Author object>, <Author: Author object>]>
# 查询作者ID为1的写的书(反向)
    # author_obj = models.Author.objects.filter(pk=1).first()
    # print(author_obj.book_set.all())

 5.2 基于双下划线的多表查询

# 查询书籍id为1的作者的姓名:2张表没有直接关联,需要通过book_authors来关联(正向)
    res1 = models.Book.objects.filter(id=1).values('authors')
    print(res1)  # <QuerySet [{'authors': 2}, {'authors': 4}]> 查询到作者ID
    res = models.Book.objects.filter(id=1).values('authors__name')
    print(res) # 作者名:<QuerySet [{'authors__name': 'jace'}, {'authors__name': 'once'}]>

 作者姓名是once写过的书的价格(反向)
res = models.Author.objects.filter(name='once').values('book__price','book__title')
print(res) # <QuerySet [{'book__price': '98.5', 'book__title': '三国演义'}]>

# 查询书籍id为1的出版社addr(正向)
res = models.Book.objects.filter(id=1).values('publish__addr')  # 这里的publish不是表面小写而是字段
print(res) # <QuerySet [{'publish__addr': '上海'}]>

# 通过出版社id=1找出版过的书(反向)
res = models.Publish.objects.filter(id=1).values('book__title')
print(res) # <QuerySet [{'book__title': '红楼梦'}]>

# 查询红楼梦作者的电话号码(正向)
res = models.Book.objects.filter(title="红楼梦").values('authors__author_detail__phone')
print(res) # <QuerySet [{'authors__author_detail__phone': '150'}]>

# 查询作者电话号码是150出版过的书籍(反向)
res = models.AuthorDetail.objects.filter(phone=150).values('author__book__title')
print(res) # <QuerySet [{'author__book__title': '红楼梦'}, {'author__book__title': '考卷'}]>

5.3 联合查询

# 查询北方出版社出版的的价格大于19的书
res = models.Book.objects.filter(price__gt='19',publish__name="北方出版社")
print(res) # <QuerySet [<Book: Book object>]>

# 查询南方出版社出版过的书,且价格大于19(反向)
res = models.Publish.objects.filter(name="南方出版社",book__price__gt=19).values('book__title')
print(res) # <QuerySet [{'book__title': '三国演义'}, {'book__title': '18岁的天空'}]>

5.4 聚合查询与分组查询

from django.db.models import Avg,Sum,Max,Min,Count
# 聚合查询
# 请所有书籍的平均价格
res = models.Book.objects.all().aggregate(Avg("price"))
print(res)

# 分组查询(group_by)
# 统计每本书作者的个数
book_list = models.Book.objects.all().annotate(author_num=Count("authors"))
for obj in book_list:
    print(obj.author_num)

# 统计每个出版社卖的最便宜的书
res = models.Publish.objects.annotate(min_price=Min("book__price"))
print([i.min_price for i in res ])
# for obj in res: # print(obj.min_price) #第二种方法: res = models.Book.objects.values("publish__name").annotate(min_price=Min("price")) print(res) # <QuerySet [{'publish__name': '工业出版社', 'min_price': '128.88'}, {'publish__name': '北方出版社', 'min_price': '90'}, {'publish__name': '南方出版社', 'min_price': '38'},
# {'publish__name': '武汉出版社', 'min_price': '38'}]>
# 统计不只一个作者的书 res = models.Book.objects.annotate(authors_num=Count("authors")).filter(authors_num__gt=1) print(res) # <QuerySet [<Book: Book object>]>


5.5 F 与 Q

# F查询:查询的条件左右两边都来自于数据库而非你自己定义
# F可以帮我们取到表中某个字段对应的值来当作我的筛选条件,而不是我认为自定义常量的条件了,实现了动态比较的效果:F 可以帮我们实现同一表中2个字段进行比较

from django.db.models import F,Q
# 查询卖出数大于库存数的书籍
# sell_book和kc_book为字段名
res = models.Book.objects.filter(sell_book__gt=F('kc_book')).values('title')
print(res)
# 将每个商品的价格提高50元
res2 = models.Book.objects.update(price=F('price') + 50)

# Q查询:能够将filter内部默认的and关系,转换成 与或非
#              逗号 默认也是 与  的关系
# 与&   或|  非~
# 查询书籍名字是西游记或价格是140的书籍
res = models.Book.objects.filter(Q(title="西游记")|Q(price=140)).values('title')
# res = models.Book.objects.filter(title="西游记",price=140).values('title')
print(res)

# 非 ~Q
# 查询书籍价格不是140的书籍名
res1 = models.Book.objects.filter(~Q(price=140)).values("title")
print(res1)

多对多表关系三种创建方式

1.全自动:ManyToManyField()自动创建第三张表
    authors = models.ManyToManyField(to='Author')
    让django orm自动帮你创建第三张表
好处:不需要自己手动添加
坏处:表字段的扩展性极差   只会帮你建外键字段  其他额外字段一概无法创建

2.纯手动(了解):无法使用跨表查询,必须自己一个表一个表手动查找
class Book(models.Model):
    name = ...
class Author(models.Model):
    name = ...            
class Book2Author(models.Model):
    book_id = models.ForeignKey(to='Book')
    author_id = models.ForeignKey(to='Author')

3.半自动:可以使用跨表查询,与全自动一样
优点:可以自己加额外的字段
class Book(models.Model): name = ... authors = models.ManyToManyField(to='Author',through='Book2Author',through_fields=('book','author')) class Author(models.Model): name = ...
  # 如果外键建在这张表 # books
= models.ManyToManyField(to='Author',through='Book2Author',through_fields=('author','book')) class Book2Author(models.Model): book = models.ForeignKey(to='Book') author = models.ForeignKey(to='Author') create_time = ... info = ...

 

posted on 2019-08-31 15:52  杨梅冲  阅读(580)  评论(0编辑  收藏  举报