Django的平常-模型層(1)

Django的平常-模型層(1)

模型層

模型層其實就是咱們應用名下的models.py文件,咱們在裏面寫入想要建立的表的表結構,以類的形式表示出來,而後經過django的ORM來實現表的建立,以及表的增刪改查等.python

django測試環境

不是正式開發項目的話,其實咱們沒必要要必定按正式的流程來,又要建html,又要寫urls,寫views,由於咱們在學習模型層的時候其實只須要經過ORM來對數據庫進行操做,因此咱們大能夠搭建一個django的測試環境,以此來實驗咱們的一些命令,建立測試環境的步驟以下:mysql

# 咱們須要在應用名下的test.py裏面寫入以下語句來搭建測試環境

#test.py

import os


if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "建立的項目名字.settings")
    import django
    django.setup()
    
    #在下方寫須要測試的對數據庫操做的代碼便可

另外有一個小點,就是咱們在經過ORM對數據庫操做的時候,若是咱們想看到ORM轉換過程當中的sql語句,須要在settings.py進行如下的配置git

# 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',
        },
    }
}

ORM查詢

ORM的概念咱們在前文已經介紹過了,下面咱們來看ORM對於數據庫的一些具體操做sql

在寫ORM語句以前咱們首先要有一個數據庫,以及配置好當前django所用的數據庫,步驟以下數據庫

# 首先,刪除或者註釋掉settings.py裏面的DATABASES選項,而後手動加一個本地數據庫的信息

# settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'mysql1',
        'USER': 'root',
        'PASSWORD': "root",
        'HOST': '127.0.0.1',
        'PORT': 3306,
        'CHARSET': 'utf8'
    }
}
# 設置過這個配置項以後咱們還須要在項目名文件夾下的__init__.py裏面寫入以下兩行代碼,以便於讓django默認的數據庫鏈接方式從MySQLdb轉換成pymysql
import pymysql
pymysql.install_as_MySQLdb()

而後咱們須要在models.py裏面寫本身想要建立的表結構django

'''咱們以書店爲例,須要建立的表爲,書籍表,做者表,做者詳情表,出版社表,其中
    書籍-出版社,一對多
    做者-做者詳情,一對一
    書籍-做者,多對多
'''

# models.py
class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8,decimal_places=2)
    publish_date = models.DateField(auto_now_add=True)
    """
    auto_now:每次修改數據的時候 都會自動更新時間
    auto_now_add:在建立數據的時候 會自動將當前時間記錄下來
    後期若是你不人爲修改的話 數據不變 
    """

    # 書籍與出版社 是一對多關係
    publish = models.ForeignKey(to='Publish')
    # 書籍與做者 是多對多
    authors = models.ManyToManyField(to='Author')
    """
    authors虛擬字段
        1.告訴orm自動幫你建立第三張關係表
        2.orm查詢的時候  可以幫助你更加方便的查詢
    """
    
    
class Publish(models.Model):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=64)
    
    
class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    # author_detail = models.ForeignKey(unique=True,to='AuthorDetail')
    author_detail = models.OneToOneField(to='AuthorDetail')
    
    
class AuthorDetail(models.Model):
    phone = models.BigIntegerField()
    addr = models.CharField(max_length=64)

單表查詢

單表查詢,顧名思義就是在一張表內進行數據查詢,下面的語句就是單表查詢所經常使用的一些方法學習

# 對數據庫的操做無外乎就是增刪改查,下面逐一介紹,下面的語句都是寫在test.py裏面,就是咱們前面搭建好的測試環境裏面
# test.py

from 應用名 import models

# 增
# 方式一,直接調用create添加數據
models.Book.objects.create(title='jpm',price=123.23,publish_date='2019-10-24')
# 方式二,生成對象,以對象.save的方式保存數據
from datetime import date
ctime = date.today()    # 時間格式是能夠直接使用date的日期的
book_obj = models.Book(title='sgyy',price=666.66,publish_date=ctime)
book_obj.save()

# 改
# 方式一,以update的方式更新數據
models.Book.objects.filter(pk=1).update(price=999.66)
# 方式二,生成對象,直接修改,而後用.save保存
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.title = '不符合社會主義核心價值觀'
book_obj.save()

# 刪除
# 篩選出符合條件的記錄直接delete()便可
models.Book.objects.filter(pk=1).delete()

# 查
    # 1.all()  查詢全部
    res = models.Book.objects.all()  
    # 惰性查詢,惰性查詢的概念在於,若是咱們只是定義了這個語句的話,他並不會執行,只有在調用它,好比打印的時候,這個語句纔會真正運行,查詢的這麼多方法裏面大都是惰性查詢
    print(res)
    for i in res:
       print(i.title)

    # 2.filter() 按照條件查詢,會匹配到全部符合條件的記錄,且filter能夠無限疊加
    res = models.Book.objects.filter(pk=2)
    print(res)

    # 3.get()  能夠拿到數據對象自己,可是若是符合條件的記錄不存在,會報錯,因此不推薦使用

    # 4.first()     拿第一個
    res = models.Book.objects.all()
    print(res)
    print(res.first())

    # 5. last()     拿最後一個
    res = models.Book.objects.all()
    print(res)
    print(res.last())

    # 6.exclude()  除此以外,即符合條件的記錄不取,取剩餘的所有記錄
    res = models.Book.objects.exclude(pk=3).filter(pk=4).filter(pk=1).filter(pk=4)
    print(res)

    # 7.values 返回數據的格式是列表套字典
    res = models.Book.objects.values('title')
    for r in res:
        print(r.get('title'))

    # 8.values_list 列表套元組
    res = models.Book.objects.values_list('title')
    print(res)

    # 9.count()  統計數據的個數
    res = models.Book.objects.count()
    res1 = models.Book.objects.all().count()
    print(res,res1)

    # 10.distinct() 去重
    """去重:數據必須是如出一轍的狀況下才能去重,包括主鍵,尤爲要注意"""
    res = models.Book.objects.all().distinct()
    res1 = models.Book.objects.values('title','price').distinct()
    print(res1)

    # 11.order_by() 以某個標準排序
    res = models.Book.objects.order_by('price')  # 默認是升序
    res1 = models.Book.objects.order_by('-price')  # 加負號就是降序
    print(res)
    print(res1)

    # 12.reverse()  注意,前面必須是先通過排序後的數據才能夠反轉,不然反轉會無效,數據順序不會發生變化
    res = models.Book.objects.order_by('price').reverse()
    print(res)

    # 13.exists()  排除符合條件的記錄,不太經常使用
    res = models.Book.objects.filter(pk=1).exists()
    print(res)


# 查詢還有一類比較好用的方法,即雙下劃線的方式
# 雙下劃線能夠實現不少很是神奇的篩選方法,好比大於小於,或者是限定範圍,還支持模糊匹配

# 1. __gt和__gte,gt是大於,gte是大於等於
res1 = models.Book.objects.filter(price__gt=300)
res2 = models.Book.objects.filter(price__gte=300)
# 上面的語句分別能夠查詢獲得價格大於300和大於等於300的圖書的對象

# 2. __lt和__lte,lt是小於,lte是小於等於
res1 = models.Book.objects.filter(price__lt=300)
res2 = models.Book.objects.filter(price__lte=300)
#上面語句能夠查詢獲得價格小於300和小於等於300的全部圖書的對象

# 3. __in和__range,in是否在其內,後面一般爲容器類型,range,是否在一個範圍內,後面一般跟元組表示範圍
res = models.Book.objects.filter(price__in=[100,200,456,]) #篩選範圍僅僅是列表內的這幾個值
res = models.Book.objects.filter(price__range=(100,499)) #篩選價格在100到499範圍內的書,這裏是顧頭不顧尾的,即價格爲100的書在範圍內,可是價格爲499的書不在範圍內.

# 咱們知道sql語句裏面的模糊匹配其實就只有like,再加上%或者_,%是任意位數的任意字符,而_是一位的任意字符

# 雙下劃線能夠實現ORM裏面的模糊匹配,經常使用的幾個方法包括contains,icontains,startswith,endswith,year,month等等.

# 1. contains 按字符模糊匹配,區分大小寫
# 2. icontains 按字符模糊匹配,不區分大小寫
# 3. startswith 以某個字符開頭
# 4. endswith 以某個字符結尾
# 5. year 用於斷定日期格式數據的年份
# 6. month 用於判斷日期格式數據的月份

多表查詢

上面咱們介紹了單表查詢的一些方法和語句,下面就來看看多表查詢經常使用的一些方法測試

咱們依然從增刪改查四個方面來分析多表間的操做:url

# 多對多表關係之間修改字段的四個方法,add,set,remove以及clear

# 1. add()添加,括號內能夠填多個值,會生成多條記錄,其實修改的是多對多的那個關係表,add的括號裏面能夠傳數字,也能夠直接傳一個對象,ORM會自動把該對象的主鍵的值取出來,傳給add使用,好比

    # 傳數字
    book_obj = models.Book.objects.filter(pk = 1).first()#這裏取出一個書籍對象
    book_obj.authors.add(1)# 書籍對象.做者,其實獲得的就是二者的關係表
    # 傳對象
    author_obj = models.Author.objects.filter(pk=1).first()
    book_obj.authors.add(author_obj)

# 2. set() 修改,用法和add類似,也支持多個值,支持傳數字和對象,不一樣的是括號裏要是一個可迭代對象,也就是說括號內不能爲一個單獨的值,而應該是列表,元素,字典或者集合這種可迭代對象
    # 傳數字
    book_obj = models.Book.objects.filter(pk = 3).first()
    book_obj.authors.set([1,])
    # 傳對象
    author_obj = models.Author.objects.filter(pk=1).first()
    book_obj.authors.set((author_obj,))#這裏是元組,注意,元組若是隻有一個值,要加逗號,否則會報錯
    
# 3. remove(),移除某條記錄,能夠傳數字和對象,支持傳多個值
    # 傳數字
    book_obj = models.Book.objects.filter(pk = 3).first()
    book_obj.authors.remove(2)
    # 傳對象
    author_obj = models.Author.objects.filter(pk=1).first()
    book_obj.authors.remove(author_obj)
# 4. clear(),清空,括號內不須要任何值,能夠直接清空當前關係表
    book_obj = models.Book.objects.filter(pk=2).first()
    book_Obj.authors.clear() # 這裏會拿到做者和書籍的關係表,而後把book表裏主鍵值爲2對應的全部數據清空

由於實際生產環境中其實仍是多表用的比較多,畢竟不少數據都不是放在一塊兒的,這時候咱們就須要經過聯表或者是經過子查詢的方式來解決數據查詢的問題,因此ORM提供給咱們兩個更好的多表查詢的方法,其原理依然仍是聯表和子查詢,不過其叫法不一樣

  1. 基於對象的跨表查詢其實就是子查詢
  2. 基於雙下劃線的跨表查詢其實就是聯表查詢.

這裏咱們還要清楚一個正向查詢和反向查詢的概念,即咱們從外鍵所在的表向外面的表查詢的時候,叫作正向查詢,反過來就叫作反向查詢.

'''基於對象的跨表查詢'''
#顧名思義,咱們要經過篩選並生成出一個對象,而後從這個對象連到其餘表,再查詢取值,好比:

# 正向查詢
    # 單個值
    book_obj = models.Book.objects.filter(title='python').first()
    print(book_obj.publish.name)#這裏用書籍對象直接.出版社,此時其實就已經到了publish表裏面,而後直接.name就能夠拿到相對應的值,這裏由於書籍對應的出版社都是單個值,因此能夠直接取值

    # 多個值
    book_obj = models.Book.objects.filter(pk = 1).first()
    print(book_obj.authors) # 咱們能夠看到這裏返回結果是  應用名.Author.None,這並不意味着咱們的語句寫錯了,而是返回的結果不是單個值,咱們取不到
    print(book_obj,authors.all())# 因此若是查詢到結果是多個值,要在後面加.all(),才能正常看到返回結果

# 反向查詢
    # 單個值
    author_detail_obj = models.AuthorDetail.objects.filter(pk=1).first()
    print(author_detail_obj.author)
    print(author_detail_obj.author.name)
    # 多個值
    publish_obj = models.Publish.objects.filter(pk = 1).first()
    print(publish_obj.book_set) # 這裏結果是 應用名.Book.None,是否是很熟悉?對,要加.all()
    print(publish_obj.book_set.all())
    #總結下來就是,反向查詢時,當查詢結果是多個值的時候,須要加_set.all()在後面,而查詢結果只有一個值的話不須要加這個
'''基於雙下劃線的跨表查詢'''
# 上文中咱們說過,基於雙下劃線的跨表查詢其實就是聯表查詢,那麼在原生sql裏面聯表方式有幾種呢?四種,即左聯left join,右聯right join,內聯inner join,全聯 union.在當前的ORM裏面咱們沒必要關心這些聯表方式,內部會幫咱們作處理,咱們須要作的只是理清楚查詢邏輯,或者說其實咱們只須要認清楚是正向查詢仍是反向查詢就能夠了.

# 和雙下劃線相匹配使用的方法就是.values()
res = models.Book.objects.filter(pk=1).values('publish__name')
print(res)
# 上面以書籍的主鍵來尋找到出版社的名字是正向查詢,那麼與之對應的反向查詢以下
res = models.Publish.objects.filter(book__pk=1),values('name')
print(res)
相關文章
相關標籤/搜索