大家都知道,原生的SQL为我们提供了分组之后查找组内数据的办法:GROUP_CONCAT方法;但是对于用Django开发的程序员来说~Django自带的ORM并没有内置这样功能的方法,而每一次遇到这样的需求如果都要用原生SQL去解决的话势必会降低我们的开发效率。

  本文为大家介绍一种在Django项目中自定义类Coucat类的方式去实现对应的效果。

表关系

现在假设我们的Django项目的book应用中有两张关联的表:book表与publish表。表结构如下:

book表:

publish表:

其中:book表的publisher_id是通过ORM语法与publish表建立关联的外键字段。

原生SQL中GROUP_CONCAT的分组查询

单表下的分组查询

按照publisher_id分组查询每组数据下的书名:

select group_concat(title),publisher_id from book_book GROUP BY(publisher_id);

结果如下:

连表下的分组查询

查找每个出版社出版的书籍的名称

select group_concat(book_book.title),book_publish.name from book_book inner join book_publish
on book_book.publisher_id = book_publish.id
group by book_publish.name;

结果如下:

ORM中自定义Concat类实现COUCAT_GROUP的效果

在我们Django项目中的lib目录下新建一个concat.py文件,文件中的内容如下:

# -*- coding:utf-8 -*-
from django.db.models import Aggregate,CharField class Concat(Aggregate):
function = 'GROUP_CONCAT'
template = '%(function)s(%(distinct)s%(expressions)s)' def __init__(self,expression,distinct=False,**extra):
super(Concat,self).__init__(
expression,
distinct='DISTINCT' if distinct else '',
output_field=CharField(),
**extra)

以上的代码就是我们实现COUCAT_GROUP效果的类。

然后,创建一条测试路由:

url(r'^concat/',views.concat),

视图函数中concat函数实现具体的功能:

from django.shortcuts import HttpResponse

from lib.concat import Concat

def concat(request):

    # 单表:用publisher_id分组,找每个分组中的书籍名称
ret = Book.objects.values('publisher_id').annotate(titles=Concat('title'))
print(ret)
#<QuerySet [{'publisher_id': 21, 'titles': 'linux,cpp,lsi'}, {'publisher_id': 22, 'titles': 'ruby,c'},
# {'publisher_id': 23, 'titles': 'go,xsd'}, {'publisher_id': 24, 'titles': 'java'}, {'publisher_id': 25, 'titles': 'python,rsb'}]> #跨表:每个出版社出版的所有的书籍
#方法一:以publish表为基准去查
ret = Publish.objects.values('name').annotate(titles=Concat('book__title'))
print(ret)
#<QuerySet [{'name': '樱桃出版社', 'titles': 'go,xsd'}, {'name': '橘子出版社', 'titles': 'ruby,c'},
# {'name': '橙子出版社', 'titles': 'python,rsb'}, {'name': '苹果出版社', 'titles': 'linux,cpp,lsi'}, {'name': '西瓜出版社', 'titles': 'java'}]>
#方法二:以book表为基准去查
ret = Book.objects.values('publisher__name').annotate(titles=Concat('title'))
print(ret)
#<QuerySet [{'publisher__name': '樱桃出版社', 'titles': 'go,xsd'}, {'publisher__name': '橘子出版社', 'titles': 'ruby,c'},
# {'publisher__name': '橙子出版社', 'titles': 'python,rsb'}, {'publisher__name': '苹果出版社', 'titles': 'linux,cpp,lsi'},
# {'publisher__name': '西瓜出版社', 'titles': 'java'}]> return HttpResponse('Concat')

大家可以看到,用法也十分简单,只需要在分组的annotate方法中加上我们定义的这个类就可以了~

自定义类实现原生SQL的GROUP_CONCAT的功能的更多相关文章

  1. Java基础知识强化之IO流笔记55:IO流练习之 自定义类模拟LineNumberReader的获取行号功能案例

    1. 自定义类模拟LineNumberReader的获取行号功能案例 2. 代码实现: (1)MyBufferedReader.java: package cn.itcast_08; import j ...

  2. legend---十、thinkphp中如何进行原生sql操作

    legend---十.thinkphp中如何进行原生sql操作 一.总结 一句话总结:query方法和execute方法 Db类支持原生SQL查询操作,主要包括下面两个方法: query方法 quer ...

  3. jpa 联表查询 返回自定义对象 hql语法 原生sql 语法 1.11.9版本

    -----业务场景中经常涉及到联查,jpa的hql语法提供了内连接的查询方式(不支持复杂hql,比如left join ,right join).  上代码了 1.我们要联查房屋和房屋用户中间表,通过 ...

  4. springdata 查询思路:基本的单表查询方法(id,sort) ---->较复杂的单表查询(注解方式,原生sql)--->实现继承类---->复杂的多表联合查询 onetomany

    springdata 查询思路:基本的单表查询方法(id,sort) ---->较复杂的单表查询(注解方式,原生sql)--->实现继承类---->复杂的多表联合查询 onetoma ...

  5. 使用原生SQL返回实体类具体实现详情

    注:可以直接复制粘贴,欢迎提出各种问题,谢谢! 因为网上查询大都是相同的,自己做时发现很多不懂,摸索了很久才弄懂,所以写了这个例子,比较容易看懂吧. 使用原生SQL查询并将结果返回实体中: (1)因为 ...

  6. hibernate使用原生SQL查询

    以下是Demo测试Hibernate 原生SQL查询: import java.util.Iterator; import java.util.List; import java.util.Map; ...

  7. 关于No Dialect mapping for JDBC type :-9 hibernate执行原生sql语句问题

    转自博客http://blog.csdn.net/xd195666916/article/details/5419316,同时感谢博主 今天做了个用hibernate直接执行原生sql的查询,报错No ...

  8. 2016/05/13 thinkphp 3.2.2 ① 数据删除及执行原生sql语句 ②表单验证

    [数据删除及执行原生sql语句] delete()  返回受影响的记录条数 $goods -> delete(30);   删除主键值等于30的记录信息 $goods -> delete( ...

  9. Django&,Flask&pyrthon原生sql语句 基本操作

    Django框架 ,Flask框架 ORM 以及pyrthon原生sql语句操作数据库 WHAT IS ORM? ORM( Object Relational Mapping) 对象关系映射 , 即通 ...

随机推荐

  1. P1012拼数

    这是一道字符串的普及—的题. 输入几组数字,怎样组合起来才可以使最后结果最大.一开始这道题类似于那道删数问题,每次删除递增序列的最后一位,达到最小.而这个题我也是想到了贪心做法,于是想逐位判断,让在前 ...

  2. Jafka源码分析——网络架构

    在kafka中.每个broker都是一个server.依照一般理解,server就是一个SocketServer,其不断接收用户的请求并进行处理.在Java中进行网络连接有两种方式一种为堵塞模式一种为 ...

  3. asp.net后台cs中的JSON格式变量在前台Js中调用方法

    //后台cs代码: using System; using System.Collections.Generic; using System.Linq; using System.Web; using ...

  4. 使用Eclipse-Maven-git做Java开发(3)--Eclipse的安装和配

    使用Eclipse-Maven-git做Java开发(3)--Eclipse的安装和配 https://my.oschina.net/songxinqiang/blog/474530

  5. Vue实现二级菜单的显示与隐藏

    <html> <head> <title>Vue实现二级菜单的显示与隐藏</title> <script src="vue.js&quo ...

  6. MySQL索引的分类、结构、使用场景

    MySQL索引分类 1.主键索引:设定为主键后数据库会自动建立索引,innodb为聚簇索引 语法: 随表一起建索引: CREATE TABLE customer (id INT(10) UNSIGNE ...

  7. Spring基础03——Spring IOC和DI概述

    1.什么是IOC与DI IOC(Inversion of Control):其思想是反转资源获取方向,传统的资源查找方式要求组件想容器发起请求查找资源,作为回应,容器适时的返回资源,而应用了IOC之后 ...

  8. .net 正则表达式

    string RegStr = @"^[0-9]*[1-9][0-9]*$"; if (Regex.IsMatch("待验证的字符串", RegStr)) { ...

  9. 北京师范大学第十五届ACM决赛-重现赛 B Borrow Classroom (树 ——LCA )

    链接:https://ac.nowcoder.com/acm/contest/3/B 来源:牛客网 Borrow Classroom 时间限制:C/C++ 3秒,其他语言6秒 空间限制:C/C++ 2 ...

  10. 小程序makePhoneCall拨打电话问题

    调用wx.makePhoneCall后肯定会弹出一个询问框,此时无论是点击确认或者取消,页面都会依次触发app.js中的onHide函数和onShow函数,所以需要注意