chapter 6
数据库/模型 最佳实践:
模型是很多Django项目的基础。
这是我们挑选的用于模型的第三方包
*South
用来做数据库迁移,这是一个很好用很常见的工具
*django-model-utils to handle common patterns like TimeStampedModel
*django-extensions 它有一个强有里的shell工具来自动装载所有app的模型
基本知识:
*拆分有太多模型的app
如果一个app中有超过20个模型,那么就要把它拆分成小的app了,可能这一个app做的东西太多了。实际操作中,一般每个app的模型不超过5个
*不是必要的情况,不要使用原生的sql
如果可以使用ORM来配置数据库操作,请优先使用。
使用原生SQL使得app的可移植性降低
Django BDFL Jacob Kaplan-Moss says (paraphrased): If it's easier to write a query using
SQL than Django, then do it. extra() is nasty and should be avoided; raw() is great and should be used where appropriate
*在需要的时候增加indexs
我们的习惯是开始不添加index,需要的时候才添加
我们考虑增加index的情况:
*index使用非常频繁,百分之10~25的查询中都需要它
*我们可以通过测试来衡量生成的indexs是否提高了查询性能
*有真实的数据或者接近真实的数据,我们可以使用index来分析
*小心模型继承
Django提供了3中模型继承的方式:abstract base classes,multi-table inberitance ,proxy models
注意:Django Abstract Base Classes!= Python Abstract Base Classes
避免 Multi-Table 继承
模型继承的案例:The TimeStampedModel 时间戳模型
# Code taken with permission from Carl Meyer's
# very useful django-model-utils
from django.db import models
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
class AutoCreatedField(models.DateTimeField):
"""
A DateTimeField that automatically populates itself at
object creation.
By default, sets editable=False, default=now
"""
def __init__(self, *args, **kwargs):
kwargs.setdefault('editable', False)
kwargs.setdefault('default', now)
super(AutoCreatedField, self).__init__(*args, **kwargs)
class AutoLastModifiedField(AutoCreatedField):
"""
A DateTimeField that updates itself on each save() of
the model.
By default, sets editable=False and default=now.
"""
def pre_save(self, model_instance, add):
value = now()
setattr(model_instance, self.attname, value)
return value
class TimeStampedModel(models.Model):
"""
An abstract base class model that provides self- updating ``created`` and ``modified`` fields.
"""
created = AutoCreatedField(_('created'))
modified = AutoLastModifiedField(_('modified'))
class Meta:
abstract = True #声明为抽象基类
测试:
# flavors/models.py
from django.db import models
from model_utils import TimeStampedModel
class Flavor(TimeStampedModel):
title = models.CharField(max_length=200)
Django的模型设计:
*从标准化开始,一定要熟悉,datebase normalization
*在没标准化之前缓存
*只有特殊需求下才可以不遵守标准
什么时候使用null 和 blank
在设置一个字段的属性的时候有 null=True and blank=True的选项,默认都是False的
具体建议请参照书中表格:ex 文本型字段 使用blank=True
模型控制器:Model Managers
可以自己定制 小案例:
from django.db import models
from django.utils import timezone
class PublishedManager(models.Manager):
def published(self, *args, **kwargs):
qs = self.get_query_set().filter(*args, **kwargs)
return qs.filter(pub_date__lte=timezone.now())
class FlavorReview(models.Model):
review = models.CharField(max_length=255)
pub_date = models.DateTimeField()
# add our custom model manager
objects = PublishedManager()
注意:1 在模型继承中,抽象基类的自定义模型控制器会遗传给孩子,实体类不会
2 不同的model class中使用时要特别小心