Django之ORM操做Mysql

1、单表操做git

# 单表查询操做基本方法
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)的对象数量

2、单表查询之双下划线操做sql

models.Tb1.objects.filter(id__lte=10, id__gt=1)   # 获取id大于1 且 小于等于10的值
 
models.Tb1.objects.filter(id__in=[11, 22, 33])   # 获取id等于十一、2二、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周来表示,由于天数是不肯定的

3、图书管理系统表设计django

表关系
    一对一
    一对多
    多对多
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()内不须要传任何参数
    """

4、Django终端打印SQL语句app

# 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')

5、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 基于对象的跨表查询:子查询spa

# 基于对象的跨表查询
# 查询书籍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 联合查询code

# 查询北方出版社出版的的价格大于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 聚合查询与分组查询orm

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 = ...
相关文章
相关标签/搜索