django同时查询两张表的数据,合并检索对象返回
原始需求:
1、一篇文章内容分N个版块,每篇文章的版块数量不同。
2、有个文章搜索功能,需要同时搜索标题和内容。
实现思路:
1、由于每篇文章的内容版块数量不同,因此将每个文章的标题和内容分开存入2张表中。
模型: #标题和属性模型 class ArticleInfoModel(models.Model): title = models.CharField(max_length=200) summary = models.TextField(null=True) author = models.ForeignKey(User, null=True) create_time = models.DateTimeField(null=True) #文章内容模型 class ArticleContentModel(models.Model): article = models.ForeignKey('ArticleInfoModel') content = models.TextField() section = models.ForeignKey('ArticleContentSectionModel') create_time = models.DateTimeField(null=True)
逻辑实现:
def search_article(request,page=1,category_id=0): try: currentPage = int(page) categoryId = int(category_id) except: pass if request.method == 'GET': return json_result(message=u'搜索文章页面!') else: searchWord = request.POST.get('search_word',None) if searchWord: try: searchWord = str(searchWord).replace(' ','') except:pass numPage = int(configs.PC_FRONT_NUM_PAGE) start = (currentPage - 1) * numPage end = start + numPage if categoryId: methodCategoryModel = CategoryModel.objects.filter(pk=categoryId, is_active=1).first() if methodCategoryModel: # 先过滤出符合条件的文章信息,然后在这些文章中检索出和关键词相匹配的文章 indexModel = ArticleInfoModel.objects.filter(status__in=[1,2,3],category=methodCategoryModel).all() else: return json_params_error(message=u'你尝试查看一个不存在的分类下的文章!') else: indexModel = MethodArticleInfoModel.objects.filter(status__in=[1,2,3]).all() # 开始检索文章标题模型 infoModel = indexModel.filter(Q(title__icontains=searchWord) | Q(summary__icontains=searchWord)).all() # 再跨表检索文章内容模型中和关键词相匹配的文章内容,并且对article去重 contentModel = ArticleInfoModel.objects.filter(methodarticlecontentmodel__content__icontains=searchWord).distinct() # 由于内容只进行关键词检索,没有对文章其他条件进行过滤,因此需要再次计算检索出的内容和其他条件的交集 tmp_content_list = set() if contentModel: content_list = set(contentModel) index_list = set(indexModel) tmp_content_list = content_list.intersection(index_list) #求内容模型和索引模型的交集 # 最后将符合条件的文章标题模型和文章内容模型合并返回 info_list = set() if infoModel: info_list = set(infoModel) # 在从文章标题模型中查找出最终汇总的模型返回 articleModel = info_list.union(tmp_content_list) else: return json_params_error(message=u'请输入要搜索的关键词!') if len(articleModel) > 0: ...
正常操作数据模型
...else: return json_params_error(message=u'暂无相关文章!')
这么做的缘由:
1、在django 1.10版本中,不支持在一个过滤条件中同时检索两张表,因此只能一张一张查询。
比如:
indexModel = ArticleInfoModel.objects.filter( Q(title__icontains=searchWords)| Q(summary__icontains=searchWords)| Q(articlecontentmodel__content__icontains=searchWords) #这是ArticleContentModel 模型 status__in=[1,2,3], category=methodCategoryModel).all()
在官方文档中提到,模型可以进行关联查询,如果没有关联关系的模型可以才用:模型名字小写__字段名字 来进行查询,
按照官方给的例子,单条过滤语句这样写没有任何问题,但是如果把这种跨表查询的语句和当前模型中需要过滤的条件写在一个过滤语句中进行查询,就拿不到想要的结果。
因此,就才用上面的方式,先过滤A表中的数据,然后跨表过滤B表中的数据。
之所以跨表过滤B表数据,是因为最终要将A,B表过滤的数据进行汇总。
由于在1.10以前版本中模型还不支持union()、intersection()这种交集、并集函数,这是在1.11版本中出的,mysql也不支持这种运算方式。
所以将A表中符合条件的模型集转换成set()类型,将B表中符合条件的模型集转换成set()类型,并计算出交集。
至此就可以实现同时检索两张表的问题。