Python学习日志10:Django+Django rest framework数据库查询后排序

由于新APP需要服务端
就使用Django进行构建
API则使用Django rest framework
使用两个月过程中踩坑无数
也暴露出Django rest framework和Django自身诸多问题
1、文档不全面
Django Queryset使用起来非常方便
但遇到一些高等查询,如联表、排序等
就出现了很多文档不全、文档缺失的情况
在解决使用Django Queryset联表查询后
紧接着又遇到Django rest framework不支持Queryset.Values()序列化的问题
所以当你需要使用两者一同构建服务端时
难免需要根据自身需求完成一部分代码

2、rest framework细微的语言习惯不同
在Django里,用__符号表现联表查询
而在rest framework序列化里,使用传统的.来代表联表下一级
相对而言,rest framework更pythonic一点
但却在此造成了与Django ORM之间的语言障碍
若不详细阅读两边的开发文档
很容易在一些小细节上浪费过多时间
所以还是建议详细阅读相关功能的文档
https://docs.djangoproject.com/

3、复杂应用举例:电影搜索
关于在使用Django搜索,按关键词分词词序、分词匹配度排序的方法demo

#生成词序权重的方法,这边写了最多3层组合,太多分词则忽略,注重用户输入时前面3个分词,如:贫穷贵公子周渝民台湾版→贫穷 公子 周渝民 台湾,只取【贫穷 公子 周渝民】的组合
def segListQDict(segList,max=3):
    from itertools import combinations
    l=((len(segList)<=max) and len(segList)) or max
    d={}
    count=0
    for x in range(l):
        combins = [c for c in  combinations(range(l), l-x)]
        dic={}
        if combins!=[()]:
            for item in combins:
                if len(item)!=1:
                    dic[count]=Q()
                    for i in item:
                        dic[count]=dic[count]&(Q(v_name__icontains=segList[i])|Q(v_yanyuan__icontains=segList[i]))
                else:
                    dic[count]=Q(v_name__icontains=segList[item[0]])|Q(v_yanyuan__icontains=segList[item[0]])
                d[count]=dic[count]
                count += 1
    return d


def cutKeyword(keyword,segList,keywordQ=Q(),orderBy='-v_id'):
    #keyword为搜索关键词,segList为分词后的list
    if keyword:
        # 用户使用符号强分割关键词情况,如用户输入符号,在segList里也会被强分词
        for k in keyword.split(' '):
            # 这里使用and相关,加强用户使用空格分词视,搜索的优先级
            keywordQ = keywordQ & Q(v_name__icontains=k) 
       # 保留词序权重

        dic=segListQDict(segList)
        # 结巴进行分析使用or或关系并入keywoedQ
        otherQ = Q()
        for seg in segList:
            #关键词中如果有特定的分类词组则提取后进入排序kDict字典
            seg, kDict = changeKeyword(seg)
            if kDict != {}:
                   #关键词中是否包含类型,比如美剧铁拳,则拆分后,将美剧列入排序top2Q
                otherQ = otherQ | Q(**clearDict(expendTypeID(kDict)))
            if len(seg)>1:
                keywordQ = keywordQ | Q(v_name__icontains=seg) | Q(v_yanyuan__icontains=seg)
        # 分词结果排序
        top1Q=Q(v_name=keyword)
        top2Q=Q(v_name__icontains=keyword)|Q(v_yanyuan__icontains=keyword)|otherQ
        if len(segList)>2:
        #具体case when then方法可以参照Django文档,楼主尝试使用replace方法失败后转而使用then
            orderBy=Case(
                When(condition=top1Q, then=0),
                When(condition=top2Q, then=1),
                When(condition=Q(dic[0]), then=2),
                When(condition=Q(dic[1]),then=3),
                When(condition=Q(dic[2]), then=4),
                When(condition=Q(dic[3]), then=5),
                When(condition=Q(dic[4]), then=6),
                When(condition=Q(dic[5]), then=7),
                When(condition=Q(dic[6]), then=8),
                default=10)
        elif len(segList)==2:
            orderBy = Case(
                When(condition=top1Q, then=0),
                When(condition=top2Q, then=1),
                When(condition=Q(dic[0]), then=2),
                When(condition=Q(dic[1]), then=3),
                When(condition=Q(dic[2]), then=4),
                default=10)
        elif len(segList)==1:
            orderBy = Case(
                When(condition=top1Q, then=0),
                When(condition=top2Q, then=1),
                When(condition=Q(dic[0]), then=2),
                default=10)
    return keywordQ,orderBy

使用时就可以在filter

XXXData.objects.using('XXX').filter(keywordQ).exclude().order_by(orderBy)

你可能感兴趣的:(Python学习日志10:Django+Django rest framework数据库查询后排序)