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 = ...
相關文章
相關標籤/搜索