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

Django中基于JSON数据源创建模型的最佳实践及优化咨询

Django商品数据导入与模型优化指南

一、现有模型优化建议

先给你的模型提几个实用的优化点,让结构更合理、维护更轻松:

  • Product模型:item作为主键没问题,但建议添加unique=True约束(虽然主键本身就是唯一的,但显式声明更清晰);另外可以给name加db_index=True,方便后续按名称快速查询。
  • Market模型:没必要手动定义id = models.IntegerField(primary_key=True, auto_created=True),Django默认会自动生成一个AutoField类型的主键id,删掉这行代码更简洁。
  • Suburb模型:建议给name和market设置unique_together约束,避免同一个市场下出现重复的郊区名称:
    class Suburb(models.Model):
        name = models.CharField(max_length=30)
        market = models.ForeignKey(Market, on_delete=models.SET_NULL, null=True)
    
        class Meta:
            unique_together = ('name', 'market')
    
  • ProductForSale模型:sale主键可以换成Django默认的AutoField,手动维护Integer主键容易出现冲突;另外给product、market字段添加db_index=True,能大幅提升关联查询的速度。

二、数据导入逻辑修正

你的现有代码有两个核心问题:没有处理suburb到Market的关联,以及Product.objects.get()可能抛出DoesNotExist异常(如果数据源里的商品ID在本地不存在)。下面是修正后的实现,还加入了批量导入优化(专门应对5万+条数据的场景):

修正后的导入代码

import json
import urllib.request
from .models import Product, Market, Suburb, ProductForSale

def import_market_products():
    # 提前加载所有郊区和市场的映射,避免循环内重复查询数据库
    suburb_market_map = {sub.name.lower(): sub.market for sub in Suburb.objects.select_related('market').all()}
    
    # 准备批量创建的列表,减少数据库IO
    product_sales_to_create = []
    
    # 遍历每个市场(假设每个市场对应专属的JSON URL)
    for market in Market.objects.all():
        url = f"your_json_url_for_market_{market.id}"  # 替换成实际的市场对应URL
        response = urllib.request.urlopen(url)
        data = json.loads(response.read())
        
        for entry in data['market_products']:
            # 处理Product:如果不存在则自动创建,避免DoesNotExist异常
            product, _ = Product.objects.get_or_create(
                item=entry['item'],
                defaults={'name': entry.get('name', '')}  # 假设JSON里可能带name字段,无则留空
            )
            
            # 处理Suburb与Market的关联:先匹配郊区,再获取对应市场
            suburb_name = entry['suburb'].lower()
            market_obj = suburb_market_map.get(suburb_name)
            if not market_obj:
                # 可根据业务需求选择跳过或自动创建郊区(这里示例为跳过)
                print(f"Suburb {entry['suburb']} not found, skipping entry {entry['id']}")
                continue
            
            # 构建ProductForSale对象暂存,不立即保存
            product_sale = ProductForSale(
                product=product,
                cost=entry['cost'],
                owner=entry['owner'],
                quantity=entry['quantity'],
                market=market_obj
            )
            product_sales_to_create.append(product_sale)
    
    # 批量创建数据,相比循环create效率提升数倍
    if product_sales_to_create:
        ProductForSale.objects.bulk_create(product_sales_to_create, batch_size=1000)

关键优化点说明

  • 用get_or_create替代get:确保数据源里的新商品ID能自动创建对应的Product记录,避免因商品不存在导致的报错。
  • 提前加载郊区-市场映射:避免在循环内反复查询数据库,大幅减少IO开销。
  • 批量创建bulk_create:把多条SQL语句合并成一个执行,处理大量数据时速度提升非常明显;设置batch_size可以避免一次性加载过多数据到内存。
  • 异常处理郊区不存在的情况:根据业务需求灵活选择跳过或自动创建郊区(如果要自动创建,需要先确认该郊区所属的市场)。

三、是否需要为每个市场单独创建模型?

完全不需要!统一用ProductForSale模型就足够了:

  • 所有市场的在售商品结构都是一致的(商品、价格、卖家、数量、关联市场),拆分模型会导致大量重复代码,维护成本极高。
  • 通过ProductForSale的market外键,完全可以区分不同市场的商品,查询时只需要添加filter(market=xxx)即可。
  • 未来如果某个市场有特殊字段需求,可以考虑用模型继承或OneToOneField关联扩展模型,而不是直接拆分主模型。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:04:03