django的數據庫原生操作sql

from django.db import connection
from django.db import transaction
from django.db.utils import (IntegrityError,OperationalError,ProgrammingError,DataError
)
from django.utils import timezoneclass Db(object):"""數據庫操作工具類,封裝了CRUD、批量操作、事務和軟刪除功能數據表必須要有:updated_at-更新時間created_at-創建時間is_deleted-軟刪除標志 0為刪除,1已刪除deleted_at-刪除時間"""# ------------------------------# 核心查詢方法# ------------------------------def execute_query(self, sql, params=None, fetchone=False, return_last_id=False):"""執行SQL查詢:param sql: SQL語句:param params: 查詢參數(元組):param fetchone: 是否只返回第一條記錄(SELECT專用):param return_last_id: 是否返回最后插入的ID(INSERT/UPDATE/DELETE專用):return: SELECT返回字典列表/單條字典,其他語句返回受影響行數或最后插入ID"""try:with connection.cursor() as cursor:cursor.execute(sql, params or ())# 打印sql# print(f"{sql}====\n===={params}")if sql.strip().lower().startswith(('select', 'show')):columns = [col[0] for col in cursor.description]results = [dict(zip(columns, row)) for row in cursor.fetchall()]return results[0] if fetchone and results else resultselse:if return_last_id:try:return cursor.lastrowidexcept AttributeError:# 如果數據庫后端不支持lastrowid,則返回受影響行數return cursor.rowcountelse:return cursor.rowcountexcept IntegrityError as e:error_msg = f"數據完整性錯誤(可能原因:主鍵沖突、唯一約束重復):{str(e)}"print(error_msg)raise ValueError(error_msg) from eexcept OperationalError as e:error_msg = f"數據庫連接/操作失敗(可能原因:數據庫未啟動、網絡中斷):{str(e)}"print(error_msg)raise ConnectionError(error_msg) from eexcept ProgrammingError as e:error_msg = f"SQL語法/表結構錯誤(可能原因:表/字段不存在、SQL拼寫錯誤):{str(e)}"print(error_msg)raise SyntaxError(error_msg) from eexcept DataError as e:error_msg = f"數據格式錯誤(可能原因:類型不匹配、長度超限):{str(e)}"print(error_msg)raise TypeError(error_msg) from eexcept Exception as e:error_msg = f"意外錯誤:{str(e)}"print(error_msg)raise# ------------------------------# 插入操作# ------------------------------def insert_data(self, table, data, auto_time=True, return_last_id=True):"""插入單條數據:param table: 表名字符串:param data: 數據字典,格式 {字段名: 值}:param auto_time: 是否自動添加時間字段(默認True):param return_last_id: 是否返回最后插入的ID:return: 最后插入的ID或受影響的行數"""fields = list(data.keys())values = list(data.values())if auto_time:now = timezone.now()fields.extend(['created_at', 'updated_at'])values.extend([now, now])placeholders = ', '.join(['%s'] * len(fields))sql = f"INSERT INTO {table} ({', '.join(fields)}) VALUES ({placeholders})"return self.execute_query(sql, values, return_last_id=return_last_id)def batch_insert(self, table, data_list, auto_time=True, batch_size=1000):"""批量插入數據(自動分批次):param table: 表名字符串:param data_list: 數據字典列表,格式 [{字段名: 值}, ...]:param auto_time: 是否自動添加時間字段(默認True):param batch_size: 每批次處理的記錄數(默認1000):return: 總共插入的行數"""if not data_list:return 0total_rows = 0total_batches = (len(data_list) + batch_size - 1) // batch_sizefor i in range(total_batches):start = i * batch_sizeend = start + batch_sizebatch_data = data_list[start:end]first_item = batch_data[0].copy()fields = list(first_item.keys())if auto_time:now = timezone.now()fields.extend(['created_at', 'updated_at'])for item in batch_data:item['created_at'] = nowitem['updated_at'] = nowplaceholders = ', '.join(['%s'] * len(fields))value_groups = [tuple(item.values()) for item in batch_data]flat_values = [val for group in value_groups for val in group]sql = f"INSERT INTO {table} ({', '.join(fields)}) VALUES "sql += ', '.join([f"({placeholders})"] * len(batch_data))rows = self.execute_query(sql, flat_values)total_rows += rowsreturn total_rows# ------------------------------# 更新操作# ------------------------------def update_data(self, table, data, where, params=None, auto_time=True, return_last_id=False):"""更新數據:param table: 表名字符串:param data: 要更新的數據字典,格式 {字段名: 值}:param where: WHERE條件(不帶WHERE關鍵字),例如 "id = %s":param params: WHERE條件的參數列表:param auto_time: 是否自動更新updated_at字段(默認True):param return_last_id: 是否返回最后插入的ID(在支持的數據庫中可能返回更新的行ID):return: 受影響的行數或最后插入ID"""set_items = []values = list(data.values())if auto_time:data['updated_at'] = timezone.now()set_items = [f"{field} = %s" for field in data.keys()]values = list(data.values())else:set_items = [f"{field} = %s" for field in data.keys()]set_clause = ', '.join(set_items)sql = f"UPDATE {table} SET {set_clause} WHERE {where}"if params:values.extend(params)return self.execute_query(sql, values, return_last_id=return_last_id)def batch_update(self, table, data_list, where_field='id', auto_time=True, batch_size=1000):"""批量更新數據(使用CASE WHEN優化):param table: 表名字符串:param data_list: 數據字典列表,每個字典必須包含where_field字段:param where_field: 用于匹配記錄的字段(默認id):param auto_time: 是否自動更新updated_at字段(默認True):param batch_size: 每批次處理的記錄數(默認1000):return: 總共更新的行數"""if not data_list:return 0total_rows = 0total_batches = (len(data_list) + batch_size - 1) // batch_sizefor i in range(total_batches):start = i * batch_sizeend = start + batch_sizebatch_data = data_list[start:end]case_clauses = []values = []update_fields = {k for item in batch_data for k in item.keys() if k != where_field}for field in update_fields:case_sql = f"{field} = CASE {where_field} "for item in batch_data:case_sql += f"WHEN %s THEN %s "values.extend([item[where_field], item[field]])case_sql += "END"case_clauses.append(case_sql)where_ids = [item[where_field] for item in batch_data]values.extend(where_ids)if auto_time:now = timezone.now()case_clauses.append(f"updated_at = %s")values.append(now)set_clause = ', '.join(case_clauses)where_placeholders = ', '.join(['%s'] * len(where_ids))sql = f"UPDATE {table} SET {set_clause} WHERE {where_field} IN ({where_placeholders})"rows = self.execute_query(sql, values)total_rows += rowsreturn total_rows# ------------------------------# 刪除/軟刪除操作# ------------------------------def soft_delete(self, table, where, params=None, return_last_id=False):"""軟刪除數據(標記is_deleted=1):param table: 表名字符串:param where: WHERE條件(不帶WHERE關鍵字),例如 "id = %s":param params: WHERE條件的參數列表:param return_last_id: 是否返回最后插入的ID(在支持的數據庫中可能返回刪除的行ID):return: 受影響的行數或最后插入ID"""data = {'is_deleted': 1, 'deleted_at': timezone.now()}return self.update_data(table, data, where, params, auto_time=False, return_last_id=return_last_id)def delete_data(self, table, where, params=None, hard_delete=False, return_last_id=False):"""刪除數據(默認軟刪除):param table: 表名字符串:param where: WHERE條件(不帶WHERE關鍵字),例如 "id = %s":param params: WHERE條件的參數列表:param hard_delete: 是否執行硬刪除(物理刪除):param return_last_id: 是否返回最后插入的ID(在支持的數據庫中可能返回刪除的行ID):return: 受影響的行數或最后插入ID"""if hard_delete:sql = f"DELETE FROM {table} WHERE {where}"return self.execute_query(sql, params, return_last_id=return_last_id)else:return self.soft_delete(table, where, params, return_last_id=return_last_id)# ------------------------------# 查詢操作# ------------------------------def get_list(self, table, where=None, params=None, order_by=None, limit=None, offset=None,with_deleted=False, only_deleted=False, fields=None):"""查詢列表數據:param table: 表名字符串:param where: WHERE條件(不帶WHERE關鍵字):param params: WHERE條件的參數列表:param order_by: 排序字段,例如 "created_at DESC":param limit: 返回記錄數限制:param offset: 偏移量(用于分頁):param with_deleted: 是否包含已刪除數據:param only_deleted: 是否只返回已刪除數據:param fields: 要返回的字段列表,默認返回所有字段:return: 符合條件的記錄列表"""if fields:select_str = ', '.join(fields)else:select_str = '*'conditions = []query_params = []if where:conditions.append(where)if params:query_params.extend(params)if not with_deleted:if only_deleted:conditions.append("is_deleted = 1")else:conditions.append("is_deleted = 0")order_str = f"ORDER BY {order_by}" if order_by else ""limit_str = f"LIMIT {limit}" if limit is not None else ""offset_str = f"OFFSET {offset}" if offset is not None else ""where_clause = " AND ".join(conditions) if conditions else ""where_str = f"WHERE {where_clause}" if where_clause else ""sql = f"SELECT {select_str} FROM {table} {where_str} {order_str} {limit_str} {offset_str}"return self.execute_query(sql, query_params)def get_one(self, table, where, params=None, with_deleted=False, only_deleted=False, fields=None):"""查詢單條數據:param table: 表名字符串:param where: WHERE條件(不帶WHERE關鍵字):param params: WHERE條件的參數列表:param with_deleted: 是否包含已刪除數據:param only_deleted: 是否只返回已刪除數據:param fields: 要返回的字段列表,默認返回所有字段:return: 符合條件的單條記錄或None"""return self.get_list(table, where, params,with_deleted=with_deleted,only_deleted=only_deleted,fields=fields,limit=1)def get_count(self, table, where=None, params=None, with_deleted=False, only_deleted=False):"""查詢記錄總數:param table: 表名字符串:param where: WHERE條件(不帶WHERE關鍵字):param params: WHERE條件的參數列表:param with_deleted: 是否包含已刪除數據:param only_deleted: 是否只返回已刪除數據:return: 記錄總數"""conditions = []query_params = []if where:conditions.append(where)if params:query_params.extend(params)if not with_deleted:if only_deleted:conditions.append("is_deleted = 1")else:conditions.append("is_deleted = 0")where_clause = " AND ".join(conditions) if conditions else ""where_str = f"WHERE {where_clause}" if where_clause else ""sql = f"SELECT COUNT(*) AS count FROM {table} {where_str}"result = self.execute_query(sql, query_params, fetchone=True)return result['count'] if result else 0# ------------------------------# 事務操作# ------------------------------def execute_transaction(self, operations):"""執行一組SQL操作作為事務:param operations: SQL操作列表,格式 [(SQL語句, 參數元組), ...]:return: 每個操作的返回結果列表:raises: 任何操作失敗時拋出異常,所有操作回滾"""with transaction.atomic():results = []for idx, (sql, params) in enumerate(operations):try:result = self.execute_query(sql, params)results.append(result)except Exception as e:raise RuntimeError(f"事務中第{idx + 1}條SQL執行失敗:{str(e)}") from ereturn results# ------------------------------# 數據恢復# ------------------------------def restore_data(self, table, where, params=None):"""恢復軟刪除的數據(is_deleted=0):param table: 表名字符串:param where: WHERE條件(不帶WHERE關鍵字),例如 "id = %s":param params: WHERE條件的參數列表:return: 受影響的行數"""data = {'is_deleted': 0, 'deleted_at': None}return self.update_data(table, data, where, params, auto_time=True)
    def get_count(self, table, where=None, params=None, with_deleted=False, only_deleted=False):"""查詢記錄總數:param table: 表名字符串:param where: WHERE條件(不帶WHERE關鍵字):param params: WHERE條件的參數列表:param with_deleted: 是否包含已刪除數據:param only_deleted: 是否只返回已刪除數據:return: 記錄總數"""conditions = []query_params = []if where:conditions.append(where)if params:query_params.extend(params)# if not with_deleted:#     if only_deleted:#         conditions.append("is_deleted = 1")#     else:#         conditions.append("is_deleted = 0")where_clause = " AND ".join(conditions) if conditions else ""where_str = f"WHERE {where_clause}" if where_clause else ""sql = f"SELECT COUNT(*) AS count FROM {table} {where_str}"result = self.execute_query(sql, query_params, fetchone=True)return result['count'] if result else 0

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/91646.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/91646.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/91646.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

FreeRTOS---基礎知識2

1. FreeRTOS 調度機制概述FreeRTOS 是一個實時操作系統(RTOS),其核心功能是通過 調度器(Scheduler) 管理多個任務的執行。調度機制決定了 何時切換任務 以及 如何選擇下一個運行的任務,以滿足實時性、優先級…

Docker安裝(精簡述版)

1. 安裝:Docker 環境(Docker desktop) #Windows架構版本查看,Win R? 輸入 ?cmd? 打開命令提示符;輸入命令?: bash echo %PROCESSOR_ARCHITECTURE%#安裝Docker desktop(安裝時勾選 WSL2&am…

Postman-win64-7.3.5-Setup.exe安裝教程(附詳細步驟+桌面快捷方式設置)?

Postman 是一款超常用的接口調試工具,程序員和測試人員用它來發送網絡請求、測試API接口、調試數據交互? 1. 雙擊安裝包? 安裝包下載地址:https://pan.quark.cn/s/4b2960d60ae9,找到你下的 Postman-win64-7.3.5-Setup.exe 文件&#xff08…

149. Java Lambda 表達式 - Lambda 表達式的序列化

文章目錄149. Java Lambda 表達式 - Lambda 表達式的序列化為什么要序列化 Lambda 表達式?Lambda 表達式的序列化規則示例代碼:序列化 Lambda 表達式代碼解析:Lambda 序列化的限制總結:149. Java Lambda 表達式 - Lambda 表達式的…

頤頓機電攜手觀遠BI數據:以數據驅動決策,領跑先進制造智能化升級

頤頓機電簽約觀遠數據,聚焦財務分析、銷售管理等場景,以 BI 數據解決方案推進數據驅動決策,助力先進制造企業提效與競爭力升級。一、合作官宣:頤頓機電 觀遠數據,開啟數據應用新征程浙江頤頓機電有限公司(…

【PHP】幾種免費的通過IP獲取IP所在地理位置的接口(部分免費部分收費)

目錄 一、獲取客戶端IP地址 二、獲取IP所在地理位置接口 1、IP域名歸屬地查詢 2、騰訊地圖 - IP定位 3、聚合數據 - IP地址(推薦) 4、高德地圖 - IP定位(推薦) 5、360分享計劃 - IP查詢 6、天聚ip地址查詢 7、百度IP地址…

【Excel】制作雙重餅圖

一、效果話不多說,直接上數據和效果圖!(示例軟件:WPS Office)類別現金刷卡小計蘋果10.005.0015.00荔枝20.0015.0035.00西瓜30.0025.0055.00總計60.0045.00105.00二、步驟(一)制作底圖插入餅圖&a…

gcc-arm-none-eabi安裝后,找不到libgcc.a的拉置

位置在:/usr/lib/gcc/arm-none-eabi/6.3.1/libgcc.a查找方法:arm-none-eabi-gcc --print-libgcc-file-name以前沒找到,是因為進錯目錄:/usr/lib/arm-none-eabi/lib

上證50期權2400是什么意思?

本文主要介紹上證50期權2400是什么意思?“上證50期權2400”通常指上證50ETF期權的某個具體合約代碼,其中“2400”是合約代碼的一部分,需結合完整代碼格式理解其含義。上證50期權2400是什么意思?一、上證50期權合約代碼的組成上證5…

發那科機器人P點位置號碼自動變更功能為禁用狀態

通過改變變量的狀態,發那科機器人可以實現,當在程序中進行記錄、修改、插入、刪除、復制/粘貼包含有P點位置號碼的行時,P點位置號碼會自動從小到大自動排列,可以實現自動排列,或者點擊編輯變更編號也可以下圖所示女變量…

什么叫湖倉一體

文章目錄概念一、理解湖倉一體:先搞懂“數據湖”和“數據倉庫”1. 數據倉庫(Data Warehouse)2. 數據湖(Data Lake)3. 傳統架構的痛點:“湖”與“倉”的割裂二、湖倉一體的核心特點:融合“湖”與…

網絡安全突發事件應急預案方案

最近有要求需要出一個網絡安全突發事件應急預案方案,本文僅就應急預案問題提出一點初步思考,意在拋磚引玉,盼各位讀者不吝賜教,共同完善對這一領域的認識。一、總則 (一)目的 為有效應對規劃建筑設計院企業…

【基于3D Gaussian Splatting的三維重建】保姆級教程 | 環境安裝 | 制作-訓練-測試自己數據集 | torch | colmap | ffmpeg | 全過程圖文by.Akaxi

目錄 一.【3DGS環境配置】 1.1 克隆3DGS倉庫 1.2 安裝Visual Studio 2022 1.2.1 下載Visual Studio 2022 1.2.2 更改環境變量 1.3 創建環境 1.3.1 創建python環境 1.3.2 離線安裝torch包 1.3.3 安裝依賴包 1.3.4安裝子模塊 (1)報錯解決&…

C#泛型委托講解

1. 泛型&#xff08;Generics&#xff09; 泛型允許編寫類型安全且可重用的代碼&#xff0c;避免裝箱拆箱操作&#xff0c;提高性能。 泛型類 // 定義泛型類 public class GenericList<T> {private T[] items;private int count;public GenericList(int capacity){items …

【DL學習筆記】DL入門指南

DL入門指南 資料課程 李沐老師 《動手學深度學習》 https://tangshusen.me/Dive-into-DL-PyTorch/李宏毅老師課程 https://speech.ee.ntu.edu.tw/~hylee/ml/2021-spring.php DL入門必掌握知識點 數據處理 &#xff1a; numpy、torch地址處理 &#xff1a; os、pathlib文件處…

在 uni-app 中進行路由跳轉前的權限驗證(檢查用戶是否登錄)

使用場景&#xff1a; 適用于需要登錄才能訪問的 uni-app 應用保護需要認證的頁面不被未授權用戶訪問統一處理路由跳轉的權限控制 /utils/cookies.js下的部分代碼內容&#xff1a; // #ifdef H5 import Cookies from js-cookie // #endif// ums const tokenKey user_center_to…

垃圾收集器ParNewCMS與底層三色標記算法詳解

垃圾收集技術詳解筆記 1. 分代收集理論 當前虛擬機的垃圾收集采用分代收集算法&#xff0c;根據對象存活周期將內存分為不同代區&#xff0c;以優化回收效率。 核心分區&#xff1a; 新生代&#xff08;Young Generation&#xff09;&#xff1a;對象存活周期短&#xff0c;約9…

全排列(回溯算法)

本文參考代碼隨想錄 給定一個 沒有重復 數字的序列&#xff0c;返回其所有可能的全排列。 示例: 輸入: [1,2,3] 輸出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ] 思路 排列是有序的&#xff0c;在排列問題中不需要startIndex&#xff1b;但排列問題需要一個…

在線任意長度大整數計算器

具體請前往&#xff1a;在線大整數計算器--支持超大整數的加減乘除,冪運算/模運算,最大公約數&#xff0c;最小公倍數

AT6668B芯片說明書

這顆北斗專用單芯片解決方案AT6668B&#xff0c;采用射頻前端與基帶處理一體化設計&#xff0c;集成北斗二號/三號雙模B1IB1C信號處理器。通過優化星歷解碼算法實現秒級衛星鎖定&#xff0c;配合硬件加速的干擾監測模塊&#xff0c;在電磁環境復雜的應用場景中仍可維持10Hz高頻…