Django Admin中Variant TabularInline嵌套Gallery TabularInline失败求助
问题:Django后台中Variant的TabularInline未显示Gallery子Inline
我想要创建Product模型,实现每个产品可添加颜色、尺寸、品牌等属性变体(Variant),且每个变体拥有专属图片集(Gallery)。我已将Gallery设为Variant的TabularInline,Variant设为Product的TabularInline,但Gallery并未在Variant的Inline中显示。以下是我的models和admin.py代码,请求解决该问题:
productapp.models代码
class Product(models.Model): title = models.CharField(max_length=200) slug = models.SlugField(max_length=250, unique=True) description = RichTextUploadingField(null=True) short_description = RichTextUploadingField(null=True) price = models.IntegerField() sku = models.CharField(max_length=200, null=True, blank=True) dimenstions = models.CharField(max_length=200, null=True, blank=True) category = models.ManyToManyField(Category, related_name='category') tag = models.ManyToManyField(Tags, related_name='tag') attribute = models.ManyToManyField(Attribute, related_name='attribute') image = models.ImageField(upload_to='shop/image', null=True, blank=True) def __str__(self): return self.title class Variant(models.Model): title = models.CharField(max_length=200) product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True) variations = models.ForeignKey(Variations, on_delete=models.SET_NULL, null=True, blank=True) regular_price = models.IntegerField() sale_price = models.IntegerField(null=True, blank=True) sku = models.CharField(max_length=200, null=True, blank=True) stock_quantity = models.IntegerField(default=0) image_id = models.IntegerField(blank=True, null=True, default=0) def __str__(self): return self.title class Gallery(models.Model): title = models.CharField(max_length=200) image = models.ImageField(upload_to='shop/gallery', null=True, blank=True) product = models.ForeignKey(Variant, null=True, on_delete=models.SET_NULL, related_name='gallery') def __str__(self): return self.title
Admin.py代码
class GalleriesInline(admin.TabularInline): model = Gallery extra = 1 readonly_fields = ('pk',) formfield_overrides = { models.CharField: {'widget': TextInput(attrs={'size':'30'})}, } class VariantInline(admin.TabularInline): model = Variant inlines = [GalleriesInline] extra = 1 readonly_fields = ('image_tag',) show_change_link = True @admin.register(Product) class ProductAdmin(admin.ModelAdmin): form = ProductForm inlines = [VariantInline] prepopulated_fields = {"slug": ["title"]} list_display = ('thumbnail_tag', 'title') readonly_fields = ('image_preview',) def image_preview(self, obj): # ex. the name of column is "image" if obj.image: return mark_safe('<img src="{0}" width="150" height="150" style="object-fit:contain" />'.format(obj.image.url)) else: return '(No image)' image_preview.short_description = 'Preview'
问题原因及修复方案
核心问题
Django原生admin不支持嵌套Inline(即Inline中嵌套另一个Inline),你当前的代码设置了VariantInline包含GalleriesInline,但原生admin只会在点击Variant的「修改」链接(因设置了show_change_link = True)进入单独编辑页面时,才会显示Gallery的Inline,不会在Product编辑页面的Variant行内直接展示。
修复方案1:使用第三方库实现嵌套Inline
使用django-nested-admin库可以直接支持嵌套Inline的显示:
- 安装依赖:
pip install django-nested-admin
- 在项目
settings.py的INSTALLED_APPS中添加:
INSTALLED_APPS = [ # ... 其他已有应用 'nested_admin', ]
- 修改admin.py代码,替换继承类:
from nested_admin import NestedTabularInline, NestedModelAdmin class GalleriesInline(NestedTabularInline): model = Gallery extra = 1 readonly_fields = ('pk',) formfield_overrides = { models.CharField: {'widget': TextInput(attrs={'size':'30'})}, } class VariantInline(NestedTabularInline): model = Variant inlines = [GalleriesInline] extra = 1 readonly_fields = ('image_tag',) show_change_link = True @admin.register(Product) class ProductAdmin(NestedModelAdmin): form = ProductForm inlines = [VariantInline] prepopulated_fields = {"slug": ["title"]} list_display = ('thumbnail_tag', 'title') readonly_fields = ('image_preview',) def image_preview(self, obj): if obj.image: return mark_safe('<img src="{0}" width="150" height="150" style="object-fit:contain" />'.format(obj.image.url)) else: return '(No image)' image_preview.short_description = 'Preview'
修复方案2:原生admin适配方案(无需第三方库)
如果不想引入外部依赖,可采用以下方式:
- 保持现有代码逻辑,点击Variant的「修改」链接进入单独页面编辑Gallery内容
- 或者调整
Gallery模型的外键命名(当前字段名product关联Variant易混淆,建议改为variant),避免后续维护出错:
class Gallery(models.Model): title = models.CharField(max_length=200) image = models.ImageField(upload_to='shop/gallery', null=True, blank=True) variant = models.ForeignKey(Variant, null=True, on_delete=models.SET_NULL, related_name='gallery') def __str__(self): return self.title
内容的提问来源于stack exchange,提问作者Farzin Shams
相关产品推荐
相关产品推荐

