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

使用Django Excel导入数据时将文本转换为外键的实现方案

问题描述

我有如下Excel表格场景:表格中的author和brand_id字段对应Product模型的外键字段。用户通过Excel添加产品时,输入的是作者用户名和品牌名称(如表1),但模型要求存储对应的外键ID(如表2)。如何将接收的文本数据动态转换为数据库外键并保存?

表1:用户输入的Excel数据

idauthorbrand_idnamebarcodeunit
user1TestBrand1Product1TST1234700
user2TestBrand2Product2TST5678380

表2:数据库需要的格式

idauthorbrand_idnamebarcodeunit
11Product1TST1234700
22Product2TST5678380

我的Product模型

class Product(models.Model):
    id = models.AutoField(primary_key=True)
    author = models.ForeignKey(User,on_delete= models.CASCADE, verbose_name='Product Author', null=True)
    brand_id = models.ForeignKey(Brand,on_delete=models.CASCADE, verbose_name="Brand Names")
    name = models.CharField(max_length=255, verbose_name="Product Name",unique=True)
    barcode = models.CharField(max_length=255, verbose_name="Barcode")
    unit = models.CharField(max_length=255,verbose_name="Product Unit") 

    def __str__(self):
        return self.name

当前添加产品的视图

@login_required(login_url="login")
def addProduct(request):
    # 其他逻辑省略
    elif 'save_file' in request.POST:
        dataset = Dataset()
        new_products = request.FILES['product_file']
        if not new_products.name.endswith('xlsx'):
            messages.info(request,'Wrong file format!')
            return redirect(".")

        imported_data = dataset.load(new_products.read(), format='xlsx')
        for data in imported_data:
            values = Product(
                data[0],
                data[1],
                data[2],
                data[3],
                data[4],
                data[5],
            )
            values.save()
        messages.success(request,"Product added from file succesfully!")
        return redirect("products")
                
    # 上下文省略
    return render(request,"product/addproduct.html",context)
解决方案

核心思路是通过文本值查询对应的User和Brand实例,获取其主键后赋值给Product的外键字段。以下是具体实现:

1. 修改视图中的导入逻辑

在循环处理每条Excel数据时,单独处理author和brand_id字段,添加异常处理避免单个数据错误导致整个导入失败:

@login_required(login_url="login")
def addProduct(request):
    # 其他逻辑省略
    elif 'save_file' in request.POST:
        dataset = Dataset()
        new_products = request.FILES['product_file']
        if not new_products.name.endswith('xlsx'):
            messages.info(request,'错误的文件格式!')
            return redirect(".")

        imported_data = dataset.load(new_products.read(), format='xlsx')
        for data in imported_data:
            # 对应Excel列顺序:data[1]是用户名,data[2]是品牌名称,需根据实际调整
            try:
                # 根据用户名查询User实例
                author_obj = User.objects.get(username=data[1])
                # 根据品牌名称查询Brand实例(假设Brand模型有name字段,需匹配实际字段名)
                brand_obj = Brand.objects.get(name=data[2])
            except User.DoesNotExist:
                messages.error(request, f"用户 {data[1]} 不存在,跳过该产品")
                continue
            except Brand.DoesNotExist:
                messages.error(request, f"品牌 {data[2]} 不存在,跳过该产品")
                continue

            # 创建Product对象,外键字段直接传入对应模型实例
            product = Product(
                author=author_obj,
                brand_id=brand_obj,
                name=data[3],
                barcode=data[4],
                unit=data[5]
            )
            try:
                product.save()
            except Exception as e:
                messages.error(request, f"产品 {data[3]} 保存失败:{str(e)}")
                continue

        messages.success(request,"产品已从文件成功添加!")
        return redirect("products")
                
    # 上下文省略
    return render(request,"product/addproduct.html",context)

2. 关键说明

  • 字段对应校验:确保Excel列的索引与代码中data[x]的取值完全匹配,避免因列顺序错误导致数据映射混乱。
  • 异常处理:捕获用户/品牌不存在的异常,跳过错误数据并给出明确提示,保证批量导入的稳定性。
  • 外键赋值方式:Django外键字段支持直接传入模型实例,无需手动提取主键,框架会自动存储实例的id值。若习惯手动指定主键,也可写成author_id=author_obj.id、brand_id_id=brand_obj.id(注意:外键字段名为brand_id时,对应的主键存储字段是brand_id_id)。
  • 可选扩展:若业务需要自动创建不存在的用户或品牌,可将get方法替换为get_or_create,示例:
    # 自动创建不存在的用户(注意:User创建可能需要补充密码等必填字段)
    author_obj, created = User.objects.get_or_create(username=data[1])
    # 自动创建不存在的品牌
    brand_obj, created = Brand.objects.get_or_create(name=data[2])
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 09:40:32