django之--模型層(ORM語法)

單表操作

# django自帶的sqlite3數據庫對日期格式不是很敏感,處理的時候容易出錯
# 將自帶的數據庫換爲mysql,之前有介紹

# 在model.py加入表結構
class User(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    register_time = models.DateField()
    '''
    DateField
    DateTimeField
        兩個重要參數
            auto_now:每次操作數據的時候,該字段會自動將當前時間更新
            auto_now_add:在創建數據的時候會自動將當前創建時間記錄下來,之後只要不修改,那麼就一直不變
    '''
    def __str__(self):
        return '對象輸出:%s' % self.name

測試腳本

  當你只是想測試django中的某一個py文件內容,那麼你可以不用書寫前後端交互的形式,而是直接寫一個測試腳本即可

  腳本代碼無論是寫在應用下的tests.py還是自己單獨開設py文件都可以

'''
測試環境的準備 去manage.py中拷貝前四行代碼 然後自己寫兩行
'''
import os
import sys

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day64.settings")
    import django

    django.setup()
# 在這個代碼塊的下面就可以測試django裏面的單個py文件了

單表的增刪改查

  • 數據的增

    # 單表操作  增刪改查
    # 數據的增加
    # 方式一:直接對應標識增加
    res = models.User.objects.create(name='xiaozhang',age=35,register_time='2020-01-11')
    print(res)
    # 方式二: 將對象方式增加
    import datetime
    now_time = datetime.datetime.now()     # 獲取當前日期
    res_obj = models.User(name='xiaoli',age=25,register_time=now_time)
    res_obj.save()
  • 數據的刪除

    # 數據的刪除
    # 方式一
    res = models.User.objects.filter(pk=2).delete()   # 刪除主鍵值是2的數據
    print(res)     # (1, {'app01.User': 1})
    '''
    pk會自動查找到當前表的主鍵字段,指代的就是當前表的主鍵字段
    用pk之後,就不需要知道當前表的主鍵字段是什麼(例如:uid,pid,sid...)
    '''
    # 方式二
    use_obj = models.User.objects.filter(pk=1).first()
    use_obj.delete()
  • 數據的修改

    # 數據的修改
    res = models.User.objects.filter(pk=3).update(name='xiaohuang')
    print(res)   # 1

    # 查找數據的方式還有get方法,該方法返回的直接就是當前數據對象,該方法不推薦使用,因爲一旦獲取的數據不存在,該方法會直接報錯
    # 查找數據的方式filter,一般還是用filter方式
    user_obj = models.User.objects.filter(pk=2)
    user_obj1 = models.User.objects.get(pk=2)
    print(user_obj)    # <QuerySet []> 返回是空,但是不不報錯
    print(user_obj1)    # 查找的主鍵值數據不存在,報錯
    user_obj.name = 'egonPPP'
    user_obj.save()

必知必會13條

  • all() 查詢所有數據

    res = models.User.objects.all()
    print(res)   # <QuerySet [<User: 對象輸出:xiaohuang>, <User: 對象輸出:xiaozhang>, <User: 對象輸出:xiaoli>]>
  • filter() 帶有過濾條件的查詢

    res = models.User.objects.filter(name='xiaoli')
    print(res)   # <QuerySet [<User: 對象輸出:xiaoli>]>
  • get() 直接拿數據對象 但是條件不存在直接報錯

    res = models.User.objects.get(pk=1)
    print(res)     # 報錯 app01.models.DoesNotExist: User matching query does not exist.
  • first() 拿queryset裏面第一個元素

    res = models.User.objects.filter(name='xiaoli').first()
    print(res)   # 對象輸出:xiaoli
  • last()   拿queryset裏面最後一個元素

    res = models.User.objects.filter(name='xiaohuang').last()
    print(res)   # 對象輸出:xiaohuang

    res = models.User.objects.all().last()
    print(res)  # 對象輸出:xiaoli
  • values() 可以指定獲取的數據字段 select name,age from ... 類似列表套字典

    res = models.User.objects.values('name','age')
    print(res)    # <QuerySet [{'name': 'xiaohuang', 'age': 20}, {'name': 'xiaozhang', 'age': 35}, {'name': 'xiaoli', 'age': 25}]>
  • values_list() 也是指定獲取數據字段    類似列表套元祖

    res = models.User.objects.values_list('name','age')
    print(res)    # <QuerySet [('xiaohuang', 20), ('xiaozhang', 35), ('xiaoli', 25)]>
  • distinct() 去重

    res = models.User.objects.values('name','age').distinct()
    print(res)   # <QuerySet [{'name': 'xiaohuang', 'age': 20}, {'name': 'xiaozhang', 'age': 35}, {'name': 'xiaoli', 'age': 25}]>
    '''
    去重一定要是一模一樣的數據纔可以,如果帶有主鍵那麼肯定是不一樣的,必須是不帶主鍵字段纔可以
    '''
  • order_by() 排序   默認是升序

    res = models.User.objects.order_by('age')   # 默認升序
    print(res)    # <QuerySet [<User: 對象輸出:xiaohuang>, <User: 對象輸出:xiaohuang>, <User: 對象輸出:xiaoli>, <User: 對象輸出:xiaozhang>]>

    res = models.User.objects.order_by('-age')    # 降序加一個減號
    print(res)     # <QuerySet [<User: 對象輸出:xiaozhang>, <User: 對象輸出:xiaoli>, <User: 對象輸出:xiaohuang>, <User: 對象輸出:xiaohuang>]>
  • reverse() 反轉的前提是 數據已經排過序了 order_by()

    res = models.User.objects.order_by('age').reverse()
    print(res)     # <QuerySet [<User: 對象輸出:xiaozhang>, <User: 對象輸出:xiaoli>, <User: 對象輸出:xiaohuang>, <User: 對象輸出:xiaohuang>]>
  • count() 統計當前數據的個數

    res = models.User.objects.count()
    print(res)      # 4
  • exclude() 排除在外

    res = models.User.objects.exclude(name='xiaohuang')
    print(res)   # <QuerySet [<User: 對象輸出:xiaozhang>, <User: 對象輸出:xiaoli>]>
  • exists() 基本用不到因爲數據本身就自帶布爾值 返回的是布爾值

    res = models.User.objects.filter(name='xiaoli').exists()
    print(res)   # True

內部查詢封裝sql語句(補充)

查詢內部封裝的sql語句
  查詢sql語句的方式,只能用於queryset對象,只有queryset對象才能夠點擊query查看內部的sql語句
    # 方式一 query   只有是queryset對象才能夠點擊query查看內部的sql語句
    res = models.User.objects.values_list('name', 'age').query
    print(res)   # SELECT `app01_user`.`name`, `app01_user`.`age` FROM `app01_user`
    # 方式二
    # 所有sql語句都能查詢,修改settings配置文件
    LOGGING = {
        'version': 1,
        'disable_existing_loggers': False,
        'handlers': {
            'console': {
                'level': 'DEBUG',
                'class': 'logging.StreamHandler',
            },
        },
        'loggers': {
            'django.db.backends': {
                'handlers': ['console'],
                'propagate': True,
                'level': 'DEBUG',
            },
        }
    }

神奇的雙下劃線查詢

    # 查詢年齡大於20歲的數據
    res = models.User.objects.filter(age__gt=20)
    print(res)   # <QuerySet [<User: 對象輸出:xiaozhang>, <User: 對象輸出:xiaoli>]>

    # 年齡小於20歲的數據
    res = models.User.objects.filter(age__lt=20)
    print(res)    # <QuerySet []>

    # 大於等於   小於等於
    res = models.User.objects.filter(age__gte=20)   # 大於等於
    print(res)   # <QuerySet [<User: 對象輸出:xiaohuang>, <User: 對象輸出:xiaozhang>, <User: 對象輸出:xiaoli>, <User: 對象輸出:xiaohuang>]>
    
    res1 = models.User.objects.filter(age__lte=20)   # 小於等於
    print(res1)   # <QuerySet [<User: 對象輸出:xiaohuang>, <User: 對象輸出:xiaohuang>]>

    # 查詢年齡是25或者35
    res = models.User.objects.filter(age__in=[25,35])
    print(res)    # <QuerySet [<User: 對象輸出:xiaozhang>, <User: 對象輸出:xiaoli>]>

    # 查詢年齡在25到35歲之間的  首尾都要
    res = models.User.objects.filter(age__range=[25,35])
    print(res)    # <QuerySet [<User: 對象輸出:xiaozhang>, <User: 對象輸出:xiaoli>]>

    # 查詢出名字裏面含有h的數據  模糊查詢   區分大小寫
    res = models.User.objects.filter(name__contains='h')
    print(res)   # <QuerySet [<User: 對象輸出:xiaohuang>, <User: 對象輸出:xiaozhang>, <User: 對象輸出:xiaohuang>]>

    # 查詢出名字裏面含有l的數據  模糊查詢  忽略大小寫
    res = models.User.objects.filter(name__icontains='l')
    print(res)   # <QuerySet [<User: 對象輸出:xiaoli>, <User: 對象輸出:xiaoLii>]>

    # # 查詢首字母是x開頭的數據
    res = models.User.objects.filter(name__startswith='x')
    print(res)

    # # 查詢最後是以x結尾的數據
    res = models.User.objects.filter(name__endswith='x')
    print(res)

    # 查詢註冊時間是2020年1月的數據
    res = models.User.objects.filter(register_time__year='2020',register_time__month='01')
    print(res)   # <QuerySet [<User: 對象輸出:xiaozhang>, <User: 對象輸出:xiaohuang>]>
    '''
    SELECT `app01_user`.`id`, `app01_user`.`name`, `app01_user`.`age`, `app01_user`.`register_time` 
        FROM `app01_user` WHERE (`app01_user`.`register_time` 
        BETWEEN '2020-01-01' AND '2020-12-31' AND EXTRACT(MONTH FROM `app01_user`.`register_time`) = 1) LIMIT 21; 
        args=('2020-01-01', '2020-12-31', 1)
    '''

多表操作

多表操作我們以圖書管理系統爲例:

  書對出版社:一對多

  書對作者:多對多

  作者對作者詳情:一對一

# 在model.py中建立ORM表結構
# 圖書表
class Book(models.Model):
    title = models.CharField(max_length=64)
    price = models.DecimalField(max_digits=8,decimal_places=2)
    publish_date = models.DateField(auto_now_add=True)
    # 一對多
    publish = models.ForeignKey(to='Publish')
    # 多對的
    authors = models.ManyToManyField(to='Authors')


# 出版社表
class Publish(models.Model):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=64)
    email = models.EmailField()   # 該字段類型不是給modles看的,而是給後面校驗性組件看的

# 作者表
class Authors(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()

    # 一對一
    author_detail = models.OneToOneField(to='AuthorDetail')

# 作者詳情表
class AuthorDetail(models.Model):
    phone = models.BigIntegerField()   # 電話號碼用BigIntegerField或者CharField
    addr = models.CharField(max_length=64)

一對多外鍵增刪改查

  • 數據的增加

    # 增加  給書籍綁定出版社
    res = models.Book.objects.create(title='三國演義',price=123.33,publish_id=1)
    res = models.Book.objects.create(title='論語',price=110.59,publish_id=2)
    res = models.Book.objects.create(title='紅樓夢',price=83.15,publish_id=1)
    res = models.Book.objects.create(title='聊齋',price=99.35,publish_id=2)
    # 虛擬字段 對象 給書籍綁定出版社
    publish_obj = models.Publish.objects.filter(pk=2).first()
    print(publish_obj.name)
    models.Book.objects.create(title='聊齋', price=123.33, publish=publish_obj) 
  • 數據的刪除

    # 刪除
    res = models.Book.objects.filter(pk=5).delete()  # 級聯刪除
    print(res)   # (3, {'app01.Book_authors': 2, 'app01.Book': 1})
  • 數據的修改

    # 修改 修改出版社
    models.Book.objects.filter(pk=2).update(publish_id=2)
    # 虛擬字段修改 對象  修改出版社信息
    publish_obj = models.Publish.objects.filter(pk=1).first()
    models.Book.objects.filter(pk=2).update(publish=publish_obj)

多對多外鍵增刪改查

  • 數據的增加

    # 增加  給書籍添加作者  add
    # 方式一
    book_obj = models.Book.objects.filter(pk=2).first()
    print(book_obj.title)     # 三國演義
    print(book_obj.authors)   # app01.Authors.None   就類似於已經到了第三張關係表
    book_obj.authors.add(1)   # 給書籍id爲2的書籍綁定一個主鍵爲1的作者   如果已經存在,則不變
    book_obj.authors.add(2, 3)   # 給書籍id爲2的書籍綁定一個主鍵爲2和3的作者
    # 方式二
    # 1、獲取書籍id爲2的書籍
    book_obj = models.Book.objects.filter(pk=2).first()
    # 2、獲取到作者表中的主鍵值爲1/2/3的數據對象
    author_obj = models.Authors.objects.filter(pk=1).first()
    author_obj1 = models.Authors.objects.filter(pk=2).first()
    author_obj2 = models.Authors.objects.filter(pk=3).first()
    print(author_obj)   # Authors object
    print(author_obj.name)   # 張三
    # 3、給獲取到的書籍添加一個作者對象
    book_obj.authors.add(author_obj)
    book_obj.authors.add(author_obj1,author_obj2)
    '''
    總結:add給第三張表關係添加數據
        括號內既可以傳數字也可以傳對象,並且都支持多個
    '''
  • 數據的刪除

    # 刪除  remove
    # 方式一
    book_obj = models.Book.objects.filter(pk=2).first()
    book_obj.authors.remove(2)    # 刪除書籍主鍵值是2的,並且作者主鍵是2的作者
    book_obj.authors.remove(1,3)    # 刪除書籍主鍵值是2的,並且作者主鍵是1和3的作者
    # 方式二
    # 1、獲取書籍id爲2的書籍
    book_obj = models.Book.objects.filter(pk=2).first()
    # 2、獲取到作者表中的主鍵值爲2/3的數據對象
    author_obj = models.Authors.objects.filter(pk=2).first()
    author_obj1 = models.Authors.objects.filter(pk=3).first()
    # 3、刪除獲取到的作者
    book_obj.authors.remove(author_obj,author_obj1)
    '''
    總結:remove
        括號內既可以傳數字也可以傳對象,並且都支持多個
    '''
  • 數據的修改

    # 修改 set   修改的值必須是一個可迭代對象
    # 方式一
    book_obj = models.Book.objects.filter(pk=2).first()
    book_obj.authors.set([1, 2])  # 括號內必須給一個可迭代對象
    book_obj.authors.set([3])    # 括號內必須給一個可迭代對象
    # 方式二
    # 1、獲取書籍id爲2的書籍
    book_obj = models.Book.objects.filter(pk=2).first()
    # 2、獲取到作者表中的主鍵值爲2/3的數據對象
    author_obj = models.Authors.objects.filter(pk=2).first()
    author_obj1 = models.Authors.objects.filter(pk=3).first()
    # 3、修改獲取到的作者對象
    book_obj.authors.set([author_obj, author_obj1])  # 括號內必須給一個可迭代對象
    '''
    總結:set  
        括號內必須傳一個可迭代對象,既可以傳數字也可以傳對象,並且都支持多個
    '''
  • 數據的清空

    # 清空 在第三張關係表中的清空某一個書籍與作者的綁定關係 clear
    book_obj.authors.clear()
    '''
    總結:clear
        括號內不要加任何參數
    '''

正反向的概念

正向:

外鍵字段在我手上,那麼我查你就是正向

反向:

外鍵字段不在我手上,那麼我查你就是反向
    # book >>> 外鍵字段在書哪裏(正向) >>> publish
    # publish >>> 外鍵字段在書哪裏(反向) >>> book
    '''
    正向查找按字段,反向查找按表名(小寫)加_set
    '''

跨表查詢(重點)

子查詢(基於對象的跨表查詢)

    # 查詢書籍主鍵爲2的出版社(書查出版社,主鍵字段在書這邊,正向)
    book_obj = models.Book.objects.filter(pk=2).first()
    res = book_obj.publish
    print(res,res.name)   # Publish object     東方出版社

    # 查詢書籍主鍵爲2的作者(書查作者,主鍵字段在書這邊,正向)
    book_obj = models.Book.objects.filter(pk=2).first()
    res = book_obj.authors.all()
    print(res)   # <QuerySet [<Authors: Authors object>, <Authors: Authors object>, <Authors: Authors object>]>

    # 查詢作者張三的電話號碼(作者查作者詳情,主鍵字段在作者這邊,正向)
    author_obj = models.Authors.objects.filter(name='張三').first()
    res = author_obj.author_detail
    print(res)    # AuthorDetail object
    print(res.phone)   # 123
    '''
    建議: 
        寫ORM語句與SQL語句類似,不要想的一次性寫完,可以寫一點看一點
        正向什麼時候需要用到all():
            當結果可能有多個的時候需要加.all() (多對多關係)
            當結果爲一個的時候,則直接拿到數據對象,無需.all() (一對一,一對多)
    '''
    # 查詢出版社是北方出版社出版的書籍(出版社查書,主鍵字段在書這邊,反向)
    publish_obj = models.Publish.objects.filter(name='北方出版社').first()
    res = publish_obj.book_set     # app01.Book.None
    res = publish_obj.book_set.all()    # <QuerySet [<Book: Book object>]>
    print(res)

    # 查詢作者是張三寫過的書(作者查書,主鍵字段在書這邊,反向)
    author_obj = models.Authors.objects.filter(name='張三').first()
    res = author_obj.book_set.all()
    print(res[1].title)    # <QuerySet [<Book: Book object>, <Book: Book object>, <Book: Book object>]>

    # 查詢手機號碼是123的作者姓名(作者詳情查詢作者,主鍵字段在作者這邊,反向)
    author_detail_obj = models.AuthorDetail.objects.filter(phone='123').first()
    res = author_detail_obj.authors    # Authors object
    print(res)
    '''
    反向查詢什麼時候需要加_set.all():
        當查詢結果可能是多個時就必須加_set.all()  (一對多,多對多)
        當查詢結果只有一個時,不需要加_set.all()  (一對一)
    '''

聯表查詢(基於雙下劃線的跨表查詢)

    # 查詢張三的手機號和作者姓名
    # 正向
    res = models.Authors.objects.filter(name='張三').values('name','author_detail__phone')
    print(res)     # <QuerySet [{'name': '張三', 'author_detail__phone': 123}]>
    # 反向
    res = models.AuthorDetail.objects.filter(authors__name='張三').values('authors__name','phone')
    print(res)     # <QuerySet [{'authors__name': '張三', 'phone': 123}]>

    # 查詢書籍主鍵爲2的出版社名稱和書的名稱
    # 正向
    res = models.Book.objects.filter(pk=2).values('publish__name','title')
    print(res)    # <QuerySet [{'publish__name': '東方出版社', 'title': '三國演義'}]>
    # 反向
    res = models.Publish.objects.filter(book__pk=2).values('name','book__title')
    print(res)    # <QuerySet [{'name': '東方出版社', 'book__title': '三國演義'}]>

    # 查詢書籍主鍵爲2的作者姓名
    # 正向
    res = models.Book.objects.filter(pk=2).values('authors__name')
    print(res)   # <QuerySet [{'authors__name': '張三'}, {'authors__name': '李四'}, {'authors__name': '王五'}]>
    # 反向
    res = models.Authors.objects.filter(book__pk=2).values('name')
    print(res)     # <QuerySet [{'name': '張三'}, {'name': '李四'}, {'name': '王五'}]>

    # 查詢書籍主鍵爲2的作者手機號碼
    # 正向
    res = models.Book.objects.filter(pk=2).values('authors__author_detail__phone')
    print(res)   # <QuerySet [{'authors__author_detail__phone': 123}, {'authors__author_detail__phone': 456}, {'authors__author_detail__phone': 789}]>
    # 反向
    res = models.AuthorDetail.objects.filter(authors__book=2).values('phone')
    print(res)    # <QuerySet [{'phone': 123}, {'phone': 456}, {'phone': 789}]>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章