Django models对象的select_related方法(减少查询次数)

表结构

先创建一个新的app
python manage.py startapp test01
在settings.py注册一下app

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'test01',
)

models.py

from django.db import models

class Person(models.Model):
    name = models.CharField('作者姓名', max_length=10)
    age = models.IntegerField('作者年龄')


class Book(models.Model):
    person = models.ForeignKey(Person, related_name='person_book')
    title = models.CharField('书籍名称', max_length=10)
    pubtime = models.DateField('出版时间')

执行如下2条语句初始化表结构

python manage.py makemigrations
python manage.py migrate

两张表关系说明:
一个人员表,一个书名表,人员有字段name和age,书名表的人员和人员表外键关联,即一本书的作者只能有一个,一个作者可以有多本书

打开sql执行过程日志到console中

# 通过此方法可以看到django ORM的详细执行过程
# 在项目的settings.py中添加如下内容
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
        }
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'level': 'DEBUG',
        },
    }
}

然后就通过数据库或者admin随便插入几条数据吧,admin这里就不赘述了

在console里测试一下效果吧

# 先看看不用select_related的效果,通过书来找到书作者的名字,子表找母表的一个字段
>>> b=models.Book.objects.get(id=1)
(0.000) QUERY = u'SELECT "test01_book"."id", "test01_book"."person_id", "test01_book"."title", "test01_book"."pubtime" FROM "test01_book" WHERE "test01_book"."id" = %s' - PARAMS = (1,); args=(1,)
>>> print b.person.name
王八
(0.000) QUERY = u'SELECT "test01_person"."id", "test01_person"."name", "test01_person"."age" FROM "test01_person" WHERE "test01_person"."id" = %s' - PARAMS = (1,); args=(1,)
# 效果就是查询了2次数据库

# 再来看看用了select_related的效果
>>> b=models.Book.objects.select_related().get(id=1)
(0.000) QUERY = u'SELECT "test01_book"."id", "test01_book"."person_id", "test01_book"."title", "test01_book"."pubtime", "test01_person"."id", "test01_person"."name", "test01_person"."age" FROM "test01_book" INNER JOIN "test01_person" ON ( "test01_book"."person_id" = "test01_person"."id" ) WHERE "test01_book"."id" = %s' - PARAMS = (1,); args=(1,)
>>> print b.person.name
王八
# 只查询了一次数据库,当然会提高性能,orm在第一次拿出book对象的时候,就顺道把他关联的表的信息拿到了,所以第二次就不用再重新查询了,类似一个信息的缓存,同理一对一关联也可以这么做
# select_related()可以接一个参数,比如book这张表除了person还有public一个字段也是外键,那么可以在()内指定'person',即可只取到person关联的,即如下3行,最后执行的sql是不同的,以免获取到大量不用的信息浪费性能
b = models.Book.objects.select_related().get(id=1)
In[4]: b = models.Book.objects.select_related('public').get(id=1)
In[5]: b = models.Book.objects.select_related('person').get(id=1)
posted @ 2016-08-30 11:12  三流码农  阅读(1367)  评论(0编辑  收藏  举报