Django小技巧16: 數據庫訪問優化
Posted November 05, 2018
#錯綜複雜
本篇分享數據庫訪問優化相關, 讀完這些並不是讓你立即去優化代碼, 更多的時候對於現有代碼的優化, 需要藉助Django Debug Toolbar來分析後, 再去相應的優化代碼, 但今天要說的是一些簡單的技巧, 用於你在編寫代碼的時候就所有規避不好用法, 使用推薦的用法.
訪問外鍵值
如果你只需外鍵的ID
Do
post.author_id
Don't
post.author.id
如果你的博文中有一個 author 的外鍵,Django 會自動將主鍵存儲在屬性author_id中, 而在author屬性則是一個惰性的數據庫引用。如果你如果使用author來訪問 ID, 數據則會多出一個額外的查詢,就會產生開銷。
批量插入Many to Many字段
Do
user.groups.add(administrators, managers)
Don't
user.groups.add(administrators) user.groups.add(managers)
Count QuerySets
如果你只需獲取 QuerySet count
Do
users = User.objects.all() users.count() # Or in template... {{ users.count }}
Don't
users = User.objects.all() len(users) # Or in template... {{ users|length }}
Empty QuerySets
如果你只想知道 QuerySets 是否爲空.
Do
groups = Group.objects.all() if groups.exists(): # Do something...
Don't
groups = Group.objects.all() if groups: # Do something...
減少不必要的查詢次數
就是之前講過的 select_related
Do
review = Review.objects.select_related('author').first() # Select the Review and the Author in a single query name = review.author.first_name
Don't
review = Review.objects.first() # Select the Review name = review.author.first_name # Additional query to select the Author
只檢索需要的字段
假設模型Invoice有50個字段,你想要創建一個表格只顯示摘要信息,包含number、date和value.
Do
# views.py # If you don't need the model instance, go for: invoices = Invoice.objects.values('number', 'date', 'value') # Returns a dict # If you still need to access some instance methods, go for: invoices = Invoice.objects.only('number', 'date', 'value') # Returns a queryset # invoices.html <table> {% for invoice in invoices %} <tr> <td>{{ invoice.number }}</td> <td>{{ invoice.date }}</td> <td>{{ invoice.value }}</td> </tr> {% endfor %} </table>
Don't
# views.py invoices = Invoice.objects.all() # invoices.html <table> {% for invoice in invoices %} <tr> <td>{{ invoice.number }}</td> <td>{{ invoice.date }}</td> <td>{{ invoice.value }}</td> </tr> {% endfor %} </table>
批量更新
使用 F()
批量更新.
Do
from django.db.models import F Product.objects.update(price=F('price') * 1.2)
Don't
products = Product.objects.all() for product in products: product.price *= 1.2 product.save()