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

Django Lead模型CSV上传优化:是否需新增List模型实现自定义名单命名筛选

方案结论

是的,新增关联的批次模型是最优实现方案,建议将模型命名为LeadImportBatch(避免和Python内置的list关键字冲突),相比直接在Lead模型中冗余存储批次名称,这种关联结构扩展性更强,后续还可以灵活补充导入时间、操作人、导入日志、备注等批次维度的属性。

具体修改步骤

1. 调整models.py

from django.db import models
from django.contrib.auth import get_user_model

User = get_user_model()

# 新增批次模型
class LeadImportBatch(models.Model):
    name = models.CharField(max_length=100, verbose_name="批次名称", unique=True)
    import_time = models.DateTimeField(auto_now_add=True, verbose_name="导入时间")
    operator = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="操作人")
    remark = models.TextField(blank=True, verbose_name="备注")

    def __str__(self):
        return self.name

class Lead(models.Model):
    # 原有字段保留,新增关联字段
    # 如果允许同一个Lead属于多个批次,换成ManyToManyField即可
    import_batch = models.ForeignKey(
        LeadImportBatch,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="leads",
        verbose_name="所属导入批次"
    )
    first_name = models.CharField(max_length=20)
    last_name = models.CharField(max_length=20)
    # 小优化:原有address字段是CharField,default=0属于类型不匹配,建议改成default=""
    address = models.CharField(default="", max_length=50)
    city = models.CharField(max_length=30, default="")
    state = models.CharField(max_length=20, default="")
    zipcode = models.IntegerField(default=0)
    phone = models.CharField(max_length=10, null=True, default="", blank=True)
    email = models.EmailField(default="")

    def __str__(self):
        return f"{self.first_name} {self.last_name}"

修改完成后执行makemigrations和migrate命令同步数据库结构。

2. 修改csv_upload.html模板

补充批次名称输入框和Django必填的CSRF校验标签:

<form action="" method="POST" enctype="multipart/form-data">
    {% csrf_token %}
    <label for="batch_name">本次导入名单名称:</label>
    <input type="text" id="batch_name" name="batch_name" required placeholder="请输入自定义批次名称">
    <br>
    <label for="file1">上传CSV文件:</label>
    <input type="file" id="file1" name="file" accept=".csv" required>
    <button type="submit">上传</button>
</form>

3. 调整csv_upload视图逻辑

先创建批次实例,再关联到本次导入的Lead数据:

import io
import csv
from django.shortcuts import render, redirect
from django.contrib import messages
from .models import Lead, LeadImportBatch

def csv_upload(request):
    template = "leads/lead_csv_upload.html"
    data = Lead.objects.all()
    prompt = {
        'order': 'CSV列顺序应为:first_name, last_name, address, city, state, zipcode, phone, email',
        'profiles': data    
    }
    if request.method == "GET":
        return render(request, template, prompt)
    
    # 先校验必填参数
    batch_name = request.POST.get('batch_name')
    csv_file = request.FILES.get('file')
    if not batch_name or not csv_file:
        messages.error(request, "请填写批次名称并选择CSV文件")
        return render(request, template, prompt)
    
    if not csv_file.name.endswith('.csv'):
        messages.error(request, "请上传后缀为.csv的文件")
        return render(request, template, prompt)
    
    # 先创建批次实例
    import_batch = LeadImportBatch.objects.create(
        name=batch_name,
        operator=request.user  # 如果不需要关联操作人可以删掉这行
    )
    
    try:
        data_set = csv_file.read().decode('UTF-8')
        io_string = io.StringIO(data_set)
        next(io_string) # 跳过表头
        for column in csv.reader(io_string, delimiter=',', quotechar="|"):
            _, created = Lead.objects.update_or_create(
                first_name=column[0],
                last_name=column[1],
                address=column[2],
                city=column[3],
                state=column[4],
                zipcode=column[5],
                phone=column[6],
                email=column[7],
                # 关联本次导入批次
                defaults={"import_batch": import_batch}
            )
        messages.success(request, f"批次【{batch_name}】导入完成")
    except Exception as e:
        # 导入失败则删除已经创建的空批次
        import_batch.delete()
        messages.error(request, f"导入失败:{str(e)}")
        return render(request, template, prompt)

    return render(request, template, {})
后续筛选使用

要查询特定批次的Lead数据,直接通过批次实例反向查询即可:

# 按批次名称筛选该批次所有Lead
batch = LeadImportBatch.objects.get(name="2024年Q3线索名单")
leads = batch.leads.all()

如果在Django Admin中注册了Lead和LeadImportBatch模型,还可以直接在后台通过批次名称筛选Lead数据。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 21:15:02