Web框架之Django_06 模型層瞭解(F查詢、Q查詢、事務、update和save、only和defer、choice屬性、bulk_create)

摘要:html

  • F查詢
  • Q查詢
  • 事務

1、F查詢

  • 在上面全部的例子中,咱們構造的過濾器都只是將字段值與某個咱們本身設定的常量作比較。若是咱們要對兩個字段的值作比較,那該怎麼作呢?
    Django 提供 F() 來作這樣的比較。F() 的實例能夠在查詢中引用字段,來比較同一個 model 實例中兩個不一樣字段的值。
    示例:
    建表:
    from django.db import models
    
    class Goods(models.Model):
        name = models.CharField(max_length=32)
        price = models.DecimalField(max_digits=8, decimal_places=2)
        remain = models.BigIntegerField()
        sold_out = models.BigIntegerField()

    插入模塊前端

    from django.db.models import F,Q

    例子:查詢賣出數量大於庫存數的商品名稱git

    res = models.Goods.objects.filter(sold_out__gt=F('remain')).values_list('name', 'sold_out', 'remain')
    print(res)
    # <QuerySet [('襪子', 600, 100), ('夾克', 20, 10)]>

    F能夠幫咱們取到表中某個字段對應的值來看成個人篩選條件,而不是我認爲自定義常量的條件了,實現了動態比較的效果sql

    Django 支持 F() 對象之間以及 F() 對象和常數之間的加減乘除和取模的操做。基於此能夠對錶中的數值類型進行數學運算
    例子:將每一個商品的價格提升50塊數據庫

    res1 = models.Goods.objects.update(price=F('price')+100)

    引伸:如何修改char字段,好比將上面的表中商品名稱所有尾部加上‘清倉’兩個字,如何操做?
    這裏須要使用2個模塊:Concat 和 Valuedjango

    from django.db.models.functions import Concat
    from django.db.models import Value
    
    res = models.Goods.objects.update(name=Concat(F('name'), Value('清倉')))

    Concat表示進行字符串的拼接操做,參數位置決定了拼接是在頭部拼接仍是尾部拼接,Value裏面是要新增的拼接值app

2、 Q查詢

  • filter()方法彙總的逗號get的條件是與的關係,若是要執行更復雜的查詢,好比or的語句,就會用到Q對象
    例子:
    查詢賣出數量大於100或者價格小於300的商品名
    from django.db.models import F,Q
    
    res = models.Goods.objects.filter(Q(sold_out__gt=100)|Q(price__lt=300)).values_list('name', 'sold_out', 'price')
    print(res)
    
    <QuerySet [('襪子清倉', 600, Decimal('129.90')), ('寸衫清倉', 10, Decimal('229.90'))]>

    對條件包裹一層Q時候,filter便可支持交叉並的比較符dom

    # 查詢庫存數是小於等於20,且賣出數不是10的產品
    res = models.Goods.objects.filter(Q(remain__lte=20)&~Q(sold_out=12)).values_list('name')

    咱們能夠組合& 和|  操做符以及使用括號進行分組來編寫任意複雜的Q 對象。函數

    同時,Q 對象可使用~ 操做符取反,這容許組合正常的查詢和取反(NOT) 查詢。性能

    # 查詢產品名包含新款或者爆款,且庫存大於60的產品
    
    res = models.Goods.objects.filter(Q(name__contains='新款')|Q(name__contains='爆款'), remain__gt=60).values_list('name')

    查詢函數能夠混合使用Q 對象和關鍵字參數。全部提供給查詢函數的參數(關鍵字參數或Q 對象)都將"AND」在一塊兒。可是,若是出現Q 對象,它必須位於全部關鍵字參數的前面

  • 重點使用方法補充:
    實例化Q對象:q = Q()
    q.connector = 'or'    #  默認q之間的條件都是與關係,這裏改爲or關係
    q.children.append(('name','sgt'))  # 插入第一個條件,注意這裏傳的是一個元祖
    q.children.append(('password','123')) # 能夠繼續插入條件
    # q對象支持直接放入filter括號內,它們之間默認是and關係,能夠經過上面的q.connect = 'or'來修改爲或關係
    models.User.objects.filter(q)    # 這裏面就是查詢的條件們,它們之間默認是與關係,能夠修改爲or關係

3、事務

  • 定義:將多個sql語句操做變成原子性操做,要麼同時成功,有一個失敗在裏面就回滾到原來的狀態,保證數據的完整性和一致性(NoSQL數據庫對事務則是部分支持)
    # 事務
    # 購買商品
    # 產品表中修改數據:賣出數+1,庫存-1
    from django.db.models import F
    from django.db import transaction
    try :
        with transaction.atomic():
            models.Goods.objects.filter(id=1).update(remain=F('remain')-1, sold_out=F('sold_out')+1)
    except Exception as e:
        print(e)

 4、補充的一些經常使用的操做

  • update()與save()的區別

    二者都是對數據的修改保存操做,可是save()函數是將數據列的所有數據項所有從新寫一遍,而update()則是針對修改的項進行鍼對的更新效率高耗時少

    因此之後對數據的修改保存用update()

  • 讓咱們經過orm對數據庫操做時候,讓終端顯示內部查詢操做sql語句:
    在Django項目的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',
            },
        }
    }

    配置好以後,再執行任何對數據庫進行操做的語句時,會自動將Django執行的sql語句打印到pycharm終端上
    補充:
    除了配置外,還能夠經過一點query便可查看查詢語句,具體操做以下:

  • only 與 defer
    拿到的是一個對象  二者是相反的
    (前提設置:設置每次操做數據庫時候都會有sql語句現實在pycharm終端,上面已說明步驟)
    先看看only:

    看看defer

  • choice屬性
    choice這個屬性,用來限制用戶作出選擇的範圍。好比說性別的選擇(男或女)
    class MyUser(models.Model):
        name = models.CharField(max_length=32)
        password = models.CharField(max_length=32)
     choices = ((1, ''), (2, ''), (3, '其它')) gender = models.CharField(choices=choices, default=1, max_length=5)

    choice接收一個元組(保證值不可變),同理每個選項也是由一個元組(value,display_name)構成。顯而易見,display_name就是要在頁面中展現的。

    如何取到value和displayname?

    好比說實例一個User對象user_obj,
    user_obj.gender = value  (經過屬性取value)
    user_obj.get_gender_display() = display_name  (經過 get_屬性_display()方法取display_name)

    在模板中能夠經過模板語言{{ user_obj.gender }}很簡單地顯示value,但不能直接調用get屬性_display方法(模板畢竟是模板語言),要解決這個問題,能夠用自定義過濾器來搞定:
    來回顧一下如何自定義過濾器:
    1,在應用名下新建一個名爲templatetags文件夾
    2,在該文件夾內新建一個py文件,名字隨意
    3,在該py文件內添加固定代碼和自定義過濾器代碼

    from django import template
    
    register = template.Library()
    
    @register.filter(name='displayName')
    def displayName(obj):
        res = obj.get_gender_display
        return res()
    
    # 視圖層:
    from django.shortcuts import render, HttpResponse,reverse
    # Create your views here.
    from app01 import models
    def index(request):
        obj = models.MyUser.objects.filter(pk=1).first()
        return render(request, 'index.html', locals())
    
    # 前端(html頁面):
    {% load my_file %}
    {{ obj|displayName}}
  • bulk_create批量插入數據
    當咱們使用orm來一次性新增不少表記錄的時候,等待結果的時間會很是的慢,若是一次性須要批量插入不少數據的時候就須要使用bulk_create來批量插入數據
    import random
    
    user_list = ['用戶[{}]'.format(i) for i in range(100)]
    data = []
    for j in user_list:
        data.append(models.MyUser(name=j, password='123', gender=str(random.choice([1, 2, 3]))))
    models.MyUser.objects.bulk_create(data)
  • select_related和prefetch_related
    def select_related(self, *fields)
        性能相關:表之間進行join連表操做,一次性獲取關聯的數據。
    
        總結:
        1. select_related主要針一對一和多對一關係進行優化。
        2. select_related使用SQL的JOIN語句進行優化,經過減小SQL查詢的次數來進行優化、提升性能。
    
    def prefetch_related(self, *lookups)
        性能相關:多表連表操做時速度會慢,使用其執行屢次SQL查詢在Python代碼中實現連表操做。
    
        總結:
        1. 對於多對多字段(ManyToManyField)和一對多字段,可使用prefetch_related()來進行優化。
        2. prefetch_related()的優化方式是分別查詢每一個表,而後用Python處理他們之間的關係。

相關文章
相關標籤/搜索