django的数据库操作很简单,一个Model.objects.all()就能把数据取出来,但是取出来的是包含了所有的字段,而我的模型Posts中有个content字段特别大,我希望取列表是不取这个字段,因此将模型中加了个自定义的函数,模型如下:

class PostsManager(models.Manager):
    def getByIdorName(self, args):
        sql_str = 'select id,title,name,content,catalog_id,author,status,crtdate,moddate,crtip,readcnt,commentcnt,isComment from %s ' \
                    %(self.model._meta.db_table)
        if args.has_key('id'):
            #此处若用get函数时,如果用户查询不存在的id会报错
            sql_str += 'where id=%s' %(int(args['id']))
            objectList = list(Posts.objects.raw(sql_str))
        elif args.has_key('field'):
            sql_str += 'where name="%s"' %(args['field'])
            objectList = list(Posts.objects.raw(sql_str))
        else:
            objectList = []
        return objectList[0] if len(objectList) > 0 else Posts()
       
    def getListByParams(self, params=None, pager=None):
        sql_str = 'select id,title,name,excerpt,catalog_id,author,status,crtdate,moddate,crtip,readcnt,commentcnt,isComment from %s ' \
                    %(self.model._meta.db_table)
        if params:
            sql_str += 'where '
            if params.has_key('catalog'):
                if not(sql_str[-6:-1] == 'where'):
                    sql_str += 'and '
                sql_str += 'catalog_id=%s ' %(int(params.get('catalog',-1)))
            if params.has_key('status'):
                if not(sql_str[-6:-1] == 'where'):
                    sql_str += 'and '
                sql_str += 'status=%s ' %(int(params.get('status',-1)))
        sql_str += ' order by crtdate desc '
        if pager:
            sql_str += ' LIMIT %s OFFSET %s' %(pager.pageSize ,pager.startSize)
        objectList = list(Posts.objects.raw(sql_str))
        return objectList            
       
class Posts(BaseModel):
    STATUS_CHOICES = (
        (0, '草稿'),
        (1, '发布'),
        (2, '加密'),
        (3, '隐藏'),
    )
    title = models.CharField("标题", max_length=200)
    name = models.CharField("URL地址名", max_length=200, null=True, blank=True, db_index=True)
    content = models.TextField("内容")
    excerpt = models.TextField("摘要")
    catalog = models.ForeignKey(Catalogs, verbose_name='目录', limit_choices_to = {'kind':'cata', 'islast': True, 'isdisplay': True})
    author = models.CharField("作者", max_length=50)
    status = models.IntegerField("状态", choices=STATUS_CHOICES, default=1)
    img = models.IntegerField("封面", max_length=20, blank=True)
    tag = models.CharField("标签", max_length=60)
    crtdate = models.DateTimeField('生成时间', auto_now_add=True)
    moddate = models.DateTimeField('修改时间', auto_now=True)
    crtip = models.IPAddressField('IP地址', blank=True)
    goodcnt = models.IntegerField('好评数', default=0)
    badcnt = models.IntegerField('差评数', default=0)
    readcnt = models.IntegerField('浏览数', default=0)
    commentcnt = models.IntegerField('回复数', default=0)
    isComment = models.BooleanField("允许评论", default=True)
    objects = PostsManager()

后来详细了解了下values函数将程序改为:

def default(self, **args):
        urlPath = '/default.html'
        pager = Pager(self.request, args, urlPath)
        pager.totalSize = Posts.objects.filter(status=1).count()
        fields = Posts().getFields(exclusion=['content'])
        postList = list(Posts.objects.filter(status=1).values(*fields).order_by('-crtdate')[pager.startSize:pager.getEndSize()])
        #postList = list(Posts.objects.getListByParams({'status':1}, pager))
        #for i in range(0, len(postList)):
        for post in postList:
            post['catalog'] = self.cataDict.get(post['catalog_id'], Catalogs())
        self.viewData['pager'] = pager.getPageList()
        self.viewData['postList'] = postList
        return self.render('/default.html')

values函数介绍:

官方文档:https://docs.djangoproject.com/en/1.3/ref/models/querysets/#values

1. values(*fields)

这个方法返回的是ValuesQuerySet,是QuerySet 的子类,也就是说,你可以用QuerySet里的方法。 需要注意的是,返回的不是list,不要直接当list来用了。对ValuesQuerySet遍历,每一个元素是“字典”dict。

当不传入参数时,返回这个model的所有字段

AppDef.objects.values()[{'creator': u'admin', 'apptype_name': u'uc3g', 'apptype_chn_name': u'3G\u95e8\u6237', 'note': u'', ...},...]

当传入参数时,只会列出你指定的参数

AppDef.objects.values('apptype_name')[{'apptype_name': u'uc3g'},...]

也可以加上filter,filter在前或者后面都是一样的

AppDef.objects.filter(pk=1).values('apptype_name')
AppDef.objects.values('apptype_name').filter(pk=1)

如果想把关联的字段也一起查出来
OneToOneField, ForeignKey 和ManyToManyField 关系的都可以。
ManyToManyField 在Django1.3版后才支持
LogTypeDef定义了一个app的ForeignKey

LogTypeDef.objects.filter(pk=6).values('pk', 'app__apptype_name')[{'pk': 6L, 'app__apptype_name': u'wapsearch'}]

如果你只想拿到app_id,可以这样
下面三种方法都是一样的,只是返回的结果名字对应你的查询语句

LogTypeDef.objects.filter(pk=6).values('pk', 'app_id')
LogTypeDef.objects.filter(pk=6).values('pk', 'app')
LogTypeDef.objects.filter(pk=6).values('pk', 'app__id')

注意在关联关系为多对多的时候,它只会帮你一条一条的列出来,而不会帮你合并为一个list。
例如会返回类型的结果:同一个pk并不会帮你合并app_id

[{pk: 6, app_id: 2}, {pk: 6, app_id: 3}]

2. 注意事项

当同时使用distinct()和values(),需要注意order_by() (或者默认 model ordering) ,会自动加入select 中作为distinct项,所以返回的结果你以为是重复的,其实是order by的字段没列出来。
如果在extra() 之后用values(),一定要把extra用到的字段也加进来;如果extra()在values()之后,extra的字段会自动加进select。
Because ManyToManyField attributes and reverse relations can have multiple related rows, including these can have a multiplier effect on the size of your result set. This will be especially pronounced if you include multiple such fields in your values() query, in which case all possible combinations will be returned. (这个不太懂什么意思,应该是当values有多个manytomanyfield的时候,会尽量合并一些)

3. 适用范围

只需要返回dict,而不需要返回model object。
只需要返回简单的数据(包括层次简单)

4. Values_list

和values一样,只是返回的不是字典而是元组。

注意点: