自定義類實現原生SQL的GROUP_CONCAT的功能


  大家都知道,原生的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方法中加上我們定義的這個類就可以了~

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM