Django Admin中实现类似Wagtail StreamField的模型选择功能
问题背景与需求
我定义了Cluster、Image、Description三个模型,对应的models.py代码如下:
class Cluster(models.Model): blockOption= (('IMG', 'IMG'),('DESC', 'DESC'),) block = models.CharField(max_length= 100, choices=blockOption) order= models.IntegerField(null=True) post = models.ForeignKey(Post, verbose_name=('Link to Post'), on_delete=models.CASCADE) class Image(models.Model): src = models.ImageField(verbose_name=('Imagefile')) captions= models.CharField(max_length= 100, null=True) cluster = models.ForeignKey(Cluster, verbose_name=('Link to Post'), on_delete=models.CASCADE) class Description(models.Model): text=models.TextField(max_length=400) cluster = models.ForeignKey(Cluster, verbose_name=('Link to Post'), on_delete=models.CASCADE)
在admin.py中,我将ImageAdminInline和DescriptionAdminInline设置为ClusterAdmin的内联模型,代码如下:
class ImageAdminInline(TabularInline): extra = 1 model = Image class DescriptionAdminInline(TabularInline): model= Description @admin.register(Cluster) class ClusterAdmin(admin.ModelAdmin): inlines= (ImageAdminInline, DescriptionAdminInline)
我希望通过ClusterAdmin实现类似Wagtail StreamField的效果:根据Cluster的block选项选择显示对应的内联模型,且不想重写Django Admin模板。此前尝试用Ajax隐藏/显示内联,但因修改模板失败,寻求可行解决方案。
可行解决方案
无需修改Django Admin模板,只需借助Admin的Media类注入自定义JavaScript,即可实现根据block选项切换显示对应内联的效果。
步骤1:修改ClusterAdmin添加媒体资源
在admin.py中为ClusterAdmin添加Media类,注入内联JS逻辑:
@admin.register(Cluster) class ClusterAdmin(admin.ModelAdmin): inlines= (ImageAdminInline, DescriptionAdminInline) class Media: extra_js = [ """ document.addEventListener('DOMContentLoaded', function() { // 获取block选择框元素 const blockSelect = document.getElementById('id_block'); // 获取两个内联表单的容器(Django自动生成ID规则:{模型名小写}_set-group) const imageInlineContainer = document.getElementById('image_set-group'); const descInlineContainer = document.getElementById('description_set-group'); // 定义切换内联显示状态的函数 function toggleInlineVisibility() { const selectedBlock = blockSelect.value; if (selectedBlock === 'IMG') { imageInlineContainer.style.display = 'block'; descInlineContainer.style.display = 'none'; } else if (selectedBlock === 'DESC') { imageInlineContainer.style.display = 'none'; descInlineContainer.style.display = 'block'; } else { // 默认状态:都隐藏(可根据需求调整) imageInlineContainer.style.display = 'none'; descInlineContainer.style.display = 'none'; } } // 页面加载完成后初始化显示状态 toggleInlineVisibility(); // 监听选择框变化,实时切换内联显示 blockSelect.addEventListener('change', toggleInlineVisibility); }); """, ]
步骤2:验证内联容器ID
Django Admin为内联表单生成的容器ID遵循{模型名小写}_set-group规则:
Image模型的内联容器ID为image_set-groupDescription模型的内联容器ID为description_set-group
如果不确定ID,可通过浏览器开发者工具(F12)查看页面元素确认。
效果说明
- 页面加载时,会根据当前
block字段的选中值自动显示对应内联表单,隐藏另一个。 - 切换
block选项时,内联表单会实时切换显示状态。 - 完全无需修改Django Admin模板文件,仅通过Admin自带的媒体注入功能实现需求。
内容的提问来源于stack exchange,提问作者Hyung Do Kim
相关产品推荐
相关产品推荐

