django查詢中extra的應用

今天有個需求需要查詢到數據庫resc_metadata字段(是一個json類型的值)中job_group去重後的值放入一個列表

一、通過pymysql完成

def set_cluster_id_value(data, hirer, resc_dict):
    db = MySQLdb.connect(SQLConf["ipAddr"], SQLConf["userName"], SQLConf["passWd"], SQLConf["table"], charset=SQLConf["charset"], port=SQLConf["port"])
    # 使用cursor()方法獲取操作遊標
    cursor = db.cursor()

    query_sql = """SELECT
                         DISTINCT(resc_metadata->'$.job_group')
                   FROM  approvedresc_rescdetail
                   WHERE resource_type = 'Job' AND bettle_id != -1000 AND hirer='%s' """ % (hirer)

    # 使用execute方法執行SQL語句
    cursor.execute(query_sql)
    job_groups = cursor.fetchall()
    exist_flag = False
    for job_group in job_groups:
    # data['job_group']返回的數據樣式是:'"abc"'
        if '"%s"'%data['job_group'] in job_group:
            exist_flag = True
            break
    if exist_flag:
        pass
    else:
        pass
    return resc_dict

二、通過extra 獲取

def set_cluster_id_value(data, hirer, resc_metadata):
    if resc_metadata['cluster_id'] == '':
        return resc_metadata
    # sql語句的!=在這裏只能用 ~Q 代替
    job_groups = RescDetail.objects.using(RescDetailConf.db).filter(Q(resource_type='Job') & ~Q(bettle_id=-1000) & Q(hirer=hirer)).extra(
        select={'job_group': "resc_metadata->'$.job_group' "}).values('job_group').distinct()
    exist_flag = False
    for job_group in job_groups:
        if '"%s"' % data['job_group'] == job_group['job_group']:
            exist_flag = True
            break
    if exist_flag:
        pass
    else:
        pass
    return resc_metadata

如果查詢的值不是json類型,直接使用distinct()就可以了。

RescDetail.objects.using(RescDetailConf.db).filter(Q(resource_type='Job') & ~Q(bettle_id=-1000) & Q(hirer=hirer)).values('job_group').distinct()

extra的介紹

extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)

有些情況下,Django的查詢語法難以簡單的表達複雜的 WHERE 子句,對於這種情況, Django 提供了 extra() QuerySet修改機制 — 它能在 QuerySet生成的SQL從句中注入新子句。

extra可以指定一個或多個 參數,例如 select, where or tables. 這些參數都不是必須的,但是你至少要使用一個!要注意這些額外的方式對不同的數據庫引擎可能存在移植性問題.(因爲你在顯式的書寫SQL語句),除非萬不得已,儘量避免這樣做.

參數之select

The select 參數可以讓你在 SELECT 從句中添加其他字段信息,它應該是一個字典,存放着屬性名到 SQL 從句的映射。

queryResult=Article.objects.extra(select={'is_recent': "create_time > '2018-04-18'"})

結果集中每個 Entry 對象都有一個額外的屬性is_recent, 它是一個布爾值,表示 Article對象的create_time 是否晚於2018-04-18. 
練習:

# in sqlite:
    article_obj=models.Article.objects.filter(nid=1)
              .extra(select={"standard_time":"strftime('%%Y-%%m-%%d',create_time)"})
              .values("standard_time","nid","title")
    print(article_obj)
    # <QuerySet [{'title': 'MongoDb 入門教程', 'standard_time': '2017-09-03', 'nid': 1}]>  

參數之where /tables:

您可以使用where定義顯式SQL WHERE子句 - 也許執行非顯式連接。您可以使用tables手動將表添加到SQL FROM子句。

where和tables都接受字符串列表。所有where參數均爲“與”任何其他搜索條件。

練習:

queryResult=models.Article
           .objects.extra(where=['nid in (1,3) OR title like "py%" ','nid>2'])
例子:
## select提供簡單數據
# SELECT age, (age > 18) as is_adult FROM myapp_person;
Person.objects.all().extra(select={'is_adult': "age > 18"})  # 加在select後面

## where提供查詢條件
# SELECT * FROM myapp_person WHERE first||last ILIKE 'jeffrey%';
Person.objects.all().extra(where=["first||last ILIKE 'jeffrey%'"])  # 加一個where條件

## table連接其它表
# SELECT * FROM myapp_book, myapp_person WHERE last = author_last
Book.objects.all().extra(table=['myapp_person'], where=['last = author_last']) # 加from後面

## params添參數
# !! 錯誤的方式 !!
first_name = 'Joe'  # 如果first_name中有SQL特定字符就會出現漏洞
Person.objects.all().extra(where=["first = '%s'" % first_name])
# 正確方式
Person.objects.all().extra(where=["first = '%s'"], params=[first_name])
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章