Django小技巧16: 数据库访问优化

#错综复杂

翻译整理自: simpleisbetterthancomplex.com

本篇分享数据库访问优化相关, 读完这些并不是让你立即去优化代码, 更多的时候对于现有代码的优化, 需要借助Django Debug Toolbar来分析后, 再去相应的优化代码, 但今天要说的是一些简单的技巧, 用于你在编写代码的时候就所有规避不好用法, 使用推荐的用法.

访问外键值

如果你只需外键的ID

post.author_id
#Do
<\>Python
post.author.id
#Don't
<\>Python

如果你的博文中有一个 author 的外键,Django 会自动将主键存储在属性author_id中, 而在author属性则是一个惰性的数据库引用。如果你如果使用author来访问 ID, 数据则会多出一个额外的查询,就会产生开销。

批量插入Many to Many字段

user.groups.add(administrators, managers)
#Do
<\>Python
user.groups.add(administrators)
user.groups.add(managers)
#Don't
<\>Python

Count QuerySets

如果你只需获取 QuerySet count

users = User.objects.all()
users.count()

# Or in template...
{{ users.count }}
#Do
<\>Python
users = User.objects.all()
len(users)

# Or in template...
{{ users|length }}
#Don't
<\>Python

Empty QuerySets

如果你只想知道 QuerySets 是否为空.

groups = Group.objects.all()
if groups.exists():
    # Do something...
#Do
<\>Python
groups = Group.objects.all()
if groups:
    # Do something...
#Don't
<\>Python

减少不必要的查询次数

就是之前讲过的 select_related

review = Review.objects.select_related('author').first()  # Select the Review and the Author in a single query
name = review.author.first_name
#Do
<\>Python
review = Review.objects.first()  # Select the Review
name = review.author.first_name  # Additional query to select the Author
#Don't
<\>Python

只检索需要的字段

假设模型Invoice有50个字段,你想要创建一个表格只显示摘要信息,包含numberdatevalue.

# 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>
#Do
<\>Python
# 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>
#Don't
<\>Python

批量更新

使用 F() 批量更新.

from django.db.models import F

Product.objects.update(price=F('price') * 1.2)
#Do
<\>Python
products = Product.objects.all()
for product in products:
    product.price *= 1.2
    product.save()
#Don't
<\>Python