Django导入带父级的ProductCategory报错:查询对象不存在
ProductCategory表为空,尝试从CSV导入商品分类时,所有带父级的行均报错:
Line number: 29 - ProductCategory matching query does not exist.
Line number: 30 - ProductCategory matching query does not exist.
Line number: 31 - ProductCategory matching query does not exist.
Line number: 32 - ProductCategory matching query does not exist.
Line number: 33 - ProductCategory matching query does not exist.
即使先导入无父级分类,再导入带父级的行,仍出现相同错误。以下是admin.py代码:
from django.contrib import admin from .models import * from import_export import resources from import_export.admin import ImportExportModelAdmin class CategoryResource(resources.ModelResource): class Meta: model = ProductCategory fields = ("id", "name", "description", "parent") class ProductCategoryAdmin(ImportExportModelAdmin): list_display = ("name", "id", "parent") search_fields = ["name", "id", "parent"] resource_class = CategoryResource class BrandResource(resources.ModelResource): class Meta: model = Brand fields = ("name", "category") class BrandAdmin(ImportExportModelAdmin): list_display = ("name", "category") search_fields = ["name", "category"] resource_class = [BrandResource] class ProductResource(resources.ModelResource): class Meta: model = Product fields = ( "id", "title", "description", "price", "color", "height", "width", "length", "weight", "material", "digital", "condition", "cordless", "hand_made", "power_usage", "device_storage", "ram", "screen_size", "cpu", "gpu", "size", "capacity", "age", "type", "gender", "sports", "business", "brand", "user", "sale", ) class ProductAdmin(ImportExportModelAdmin): list_display = ("title", "category", "price", "business") search_fields = ["title", "category"] resource_classes = [ProductResource] class ProductImageAdmin(admin.ModelAdmin): list_display = ("product", "image") search_fields = ["gallery"] class ProductVideoAdmin(admin.ModelAdmin): list_display = ("product", "video") search_fields = ["product"] class CartItemAdmin(admin.ModelAdmin): list_display = ('cart', 'product', 'quantity', 'total_price') search_fields = ['cart__user__username', 'product__title'] list_filter = ['cart__user', 'product'] def total_price(self, obj): return obj.total_price() total_price.short_description = 'Total Price' class CartItemInline(admin.TabularInline): model = CartItem extra = 0 readonly_fields = ['total_price'] fields = ['product', 'quantity', 'total_price'] def total_price(self, obj): if obj.product and obj.quantity: return obj.product.price * obj.quantity return 0 total_price.short_description = 'Total Price' def get_extra(self, request, obj=None, **kwargs): return 1 def has_add_permission(self, request, obj): return obj is not None class UserCartAdmin(admin.ModelAdmin): list_display = ("user", "display_items") search_fields = ["user"] inlines = [CartItemInline] def display_items(self, obj): items = obj.items.all() return ", ".join([f"{item.quantity} x {item.product.title}" for item in items]) display_items.short_description = 'Items in Cart' admin.site.register(Product, ProductAdmin) admin.site.register(ProductCategory, ProductCategoryAdmin) admin.site.register(Brand, BrandAdmin) admin.site.register(ProductImage, ProductImageAdmin) admin.site.register(ProductVideo, ProductVideoAdmin) admin.site.register(CartItem, CartItemAdmin) admin.site.register(Cart, UserCartAdmin)
问题原因
django-import-export默认处理外键字段(比如parent)时,会尝试用CSV中的值去查询已存在的ProductCategory对象,若找不到就报错。即使先导入父分类,若CSV中父分类的id和系统自动生成的id不匹配,或者未配置导入规则让系统识别要创建新对象,仍会触发错误。
修复步骤
修改
CategoryResource配置
明确指定导入标识为id,并配置外键字段的匹配规则,让系统按CSV中的id创建对象,同时正确关联父分类:from import_export import fields from import_export.widgets import ForeignKeyWidget class CategoryResource(resources.ModelResource): # 显式配置parent字段的外键匹配规则,用id关联 parent = fields.Field( column_name='parent', attribute='parent', widget=ForeignKeyWidget(ProductCategory, 'id') ) class Meta: model = ProductCategory fields = ("id", "name", "description", "parent") # 指定用id作为导入的唯一标识,强制按CSV中的id创建/匹配对象 import_id_fields = ('id',) # 跳过未变更的行,避免重复导入报错(可选) skip_unchanged = False report_skipped = False调整CSV文件格式
- 确保所有父分类的行出现在子分类行之前,这样导入时父分类先被创建,子分类可以找到对应的父对象。
parent列的值必须对应父分类的id,无父级的分类该列留空或填写空字符串。- 手动指定CSV中所有分类的
id,确保父分类的id和子分类parent列的值完全一致(不要让系统自动生成id,否则会导致关联失败)。
验证导入流程
直接导入包含所有分类(父+子)的CSV文件即可,无需分两次导入。若仍报错,检查CSV中id和parent列的数值是否对应,以及父分类行是否确实在子分类行之前。
内容的提问来源于stack exchange,提问作者crawlingdev

