You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django导入CSV时忽略已有重复数据,允许同批次重复

高效导入CSV并忽略数据库已存在记录的方案

针对你的需求,这里提供两种比“查询首尾日期范围再比对”更高效的实现方式,核心都是减少数据库查询次数,同时满足“允许同一次导入内重复、忽略库中已有记录”的要求:

方案一:利用ORM批量查询+过滤,适合Django原生写法

这种方式仅需1次数据库查询,就能过滤掉所有已存在的记录,再批量插入剩余数据:

  1. 读取CSV数据:完整读取CSV内容到内存,保留所有重复项:
import csv
from datetime import datetime
from decimal import Decimal
from myapp.models import Transaction

transactions_data = []
with open('transactions.csv', 'r') as f:
    reader = csv.DictReader(f)
    for row in reader:
        # 根据CSV格式转换字段类型,示例格式可自行调整
        transaction = {
            'date': datetime.strptime(row['date'], '%Y-%m-%d').date(),
            'description': row['description'].strip(),
            'amount': Decimal(row['amount'])
        }
        transactions_data.append(transaction)
  1. 提取唯一键集合:避免重复查询,先把所有记录的(date, description, amount)组合提取为唯一集合:
unique_keys = {(t['date'], t['description'], t['amount']) for t in transactions_data}
  1. 批量查询已存在记录:用一次查询找出数据库中已有的组合:
from django.db.models import Q

# 构造多条件查询
query = Q()
for date, desc, amt in unique_keys:
    query |= Q(date=date) & Q(description=desc) & Q(amount=amt)

# 仅查询需要的字段,转成集合方便快速比对
existing_records = set(Transaction.objects.filter(query).values_list('date', 'description', 'amount'))
  1. 过滤并批量插入:过滤掉已存在的记录,用bulk_create批量插入剩余数据:
to_insert = [
    Transaction(**t)
    for t in transactions_data
    if (t['date'], t['description'], t['amount']) not in existing_records
]

if to_insert:
    Transaction.objects.bulk_create(to_insert)

方案二:利用SQLite原生语句+临时表,适合大数据量场景

如果CSV数据量极大,ORM批量查询存在性能瓶颈,可以直接在数据库层面完成操作,天然支持保留同批次重复记录:

  1. 创建临时表:
from django.db import connection

with connection.cursor() as cursor:
    # 创建与Transaction结构一致的临时表
    cursor.execute("""
        CREATE TEMPORARY TABLE temp_transaction (
            date DATE,
            description TEXT,
            amount DECIMAL
        )
    """)
  1. 批量导入CSV到临时表:
with connection.cursor() as cursor:
    params = [(t['date'], t['description'], t['amount']) for t in transactions_data]
    cursor.executemany("""
        INSERT INTO temp_transaction (date, description, amount)
        VALUES (?, ?, ?)
    """, params)
  1. 从临时表插入正式表,忽略已存在记录:
with connection.cursor() as cursor:
    # 通过LEFT JOIN筛选出正式表中不存在的记录
    cursor.execute("""
        INSERT INTO transaction (date, description, amount)
        SELECT t.date, t.description, t.amount
        FROM temp_transaction t
        LEFT JOIN transaction tr
            ON t.date = tr.date 
            AND t.description = tr.description 
            AND t.amount = tr.amount
        WHERE tr.id IS NULL
    """)
    connection.commit()

# 临时表会在数据库连接关闭后自动销毁,无需手动删除

这个方案的优势是所有操作在数据库内部完成,避免了大量数据在Python与数据库间传输,性能更高。


内容的提问来源于stack exchange,提问作者speg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 22:10:43