Django的ORM中使用CASE-THEN-ELSE子句批量過濾更新數據的方法

最近有一個新的需求場景,需要根據不同的過濾條件修改數據爲相應的內容,比如id=n時修改name='name_n'。大量的這種操作肯定需要批量處理,否則一條一條修改效率是很低的。Mysql中可以使用CASE-THEN-ELSE子句實現這樣的效果,Django的ORM也提供了相應的方法,如下所示:

參考官方文檔:https://docs.djangoproject.com/en/2.2/ref/models/conditional-expressions/

# -*- coding:utf-8 -*-
from django.db import models
from datetime import datetime
from django.db.models import Case, When, Value, Q


class Book(models.Model):
    book_id = models.BigAutoField('書籍ID', primary_key=True)
    book_name = models.CharField('書名', max_length=20, db_index=True, default='')
    update_time = models.DateTimeField('更新時間', default=datetime.now)  # 不要使用auto_now=True
    create_time = models.DateTimeField('創建時間', auto_now_add=True)

    def __str__(self):
        return 'id: %s, book_name: %s, update_time: %s, create_time: %s' % (self.book_id, self.book_name, self.update_time, self.create_time)

# 初始化數據
book_ids = list(range(1, 10))
books = [Book(book_id=book_id, book_name='the_book_name') for book_id in book_ids]
Book.objects.bulk_create(books)

# 單個過濾條件
whens = [When(book_id=book_id, then=Value('book_name_id_%s' % book_id)) for book_id in book_ids]
books = Book.objects.filter(book_id__in=book_ids)  # 使用條件過濾限定範圍,提高效率
# Django源碼中sql模板爲'CASE %(cases)s ELSE %(default)s END',default參數默認值爲None
# 如果要使不滿足Case條件的記錄不被修改,設置default爲字段名,如下所示,否則字段值會被修改爲NULL
books.update(book_name=Case(*whens, default='book_name'), update_time=datetime.now())
print(Book.objects.filter(book_id__in=book_ids).all()[:len(book_ids)])

# 多個過濾條件
when = When(Q(book_id__gte=5) & Q(update_time__lte=datetime(2019, 12, 12, 12, 12, 12)), then=Value('book_name_id_gte_5_&_update_time_lte_time'))
books = Book.objects.filter(book_id__in=book_ids)  # 使用條件過濾限定範圍,提高效率
books.update(book_name=Case(when, default='book_name'), update_time=datetime.now())
print(Book.objects.filter(book_id__in=book_ids).all()[:len(book_ids)])

# 按照不同規則修改字段
when_one = When(book_id__gte=5, then=Value('book_name_id_gte_5'))  # 規則一
when_tow = When(book_id__lte=3, then=Value('book_name_id_lte_3'))  # 規則二
books = Book.objects.filter(book_id__in=book_ids)  # 使用條件過濾限定範圍,提高效率
books.update(book_name=Case(when_one, when_tow, default='book_name'), update_time=datetime.now())
print(Book.objects.filter(book_id__in=book_ids).all()[:len(book_ids)])

# 按照不同規則同時修改多個字段
when_one = When(book_id__gte=5, then=Value(datetime(2019, 12, 12, 12, 12, 12)))  # 規則一
when_tow = When(book_id__lte=4, then=Value('book_name_id_lte_4'))  # 規則二
books = Book.objects.filter(book_id__in=book_ids)  # 使用條件過濾限定範圍,提高效率
books.update(create_time=Case(when_one, default='create_time'), book_name=Case(when_tow, default='book_name'), update_time=datetime.now())
print(Book.objects.filter(book_id__in=book_ids).all()[:len(book_ids)])

 

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