如何在模型中没有表达 FK 关系的管理更改页面中的字段上实现 add/edit 链接?
How to implement the add/edit links on a field in the admin change page that does not have an expressed FK relationship in the model?
我有一个 Django 3.x 网站。共有 3 个模型,其中 Document
、MetaData
、MetaDataValue
。 MetaDataValue
模型与 MetaData
模型有外键关系。
在一个简单的世界中,会有一个从MetaData
到Document
的外键关系。然后 DocumentAdmin
会将 MetaData
字段显示为下拉列表,其中填充了适当的 MetaDataValues
。下拉列表旁边还会有 edit/add (pencil/plus) 链接,以允许用户 edit/add 那个 MetaData
对象的 MetaDataValue
。
但是,该项目的要求之一是在 运行 之前不定义哪些或多少 MetaData
对象将与特定的 Document
类型相关联。这些关联是通过另一组模型实现的。因此,Document
管理更改页面在 运行 时将不同的 MetaData
字段添加到更改管理页面,方法是查看与此关联的 MetaData
字段的数据库Document
的类型,然后通过 get_fieldsets
方法将它们添加到字段集中。
这种设计的含义是不能 edit/add 值到 Document
管理更改页面上的特定 MetaData
字段,因为,我假设,Django 丢失了底层的外国Document
和 MetaData
模型之间的关键关系,因为字段集是在管理员的 get_fieldsets
方法中生成的。
我可以添加几页代码来显示 MetaData
字段是如何在 运行 时间生成的,但我认为这不会使描述更清楚。我已经查看了为上述“简单世界”示例生成的页面源和字段集,但看不到 Django 在哪里确定何时将 edit/change 链接添加到特定外键字段的下拉列表中。
我的问题是,如何将铅笔和加号添加到 Document
管理更改页面中显示的这些 MetaData
字段,并让用户选择 add/edit该特定 MetaData
对象的 MetaDataValue
?我可以只创建一些 Ajax 调用并自己完成所有繁重的工作,但我更愿意尽可能多地利用 Django 基础架构,而不是重新发明不必要的东西。
谢谢!
马克
我找到了使用 RelatedFieldWidgetWrapper
的解决方案。我将这个小部件包装器添加到我所有需要绿色加号(添加)和黄色铅笔(编辑)的选择中。
这里 post 的代码太多了,但这是它的核心。我的数据库 table MetaData
有所有字段的名称,MetaDataValue
有每个元数据字段的值。元数据用于描述文档(文本、视频、图像),但MetaData
模型和Document
模型之间没有FK关系。元数据和文档之间的关系包含在另一个 table 的 JSON 字段中。 MetaData
table 还具有用于该元数据字段的 Django 字段类型。还有另一个 table 确定哪些元数据字段适用于哪种文档类型(图像、文本、视频)。对于所有 ModelChoiceFields
,我添加了字段和小部件(Select
包装在 RelatedFieldWidgetWrapper
中)。
elif (metadata_names[i].field_type == MetaData.MODELCHOICEFIELD):
fields[metadata_names[i].name] = forms.ModelChoiceField(queryset=MetaDataValue.objects.filter(metadata_id=metadata_names[i].metadata_id).order_by('value'), required=False, label=metadata_names[i].label, help_text=metadata_names[i].help_text)
# add the green plus (add) and pencil (edit) links to each select field
fields[metadata_names[i].name].widget = RelatedFieldWidgetWrapper(fields[metadata_names[i].name].widget, MetaDataValue._meta.get_field('tag_value'), admin_site, can_add_related=True, can_change_related=True)
if 'documentType_id' in fields:
# Editing/add a new document type seems like a bad idea, as document type is used a lot in the processing logic
fields['documentType_id'].widget.can_add_related = False
fields['documentType_id'].widget.can_change_related = False
困难的部分是为 RelatedFieldWidgetWrapper
获取正确的参数。该小部件的文档有点稀疏,因为我认为它是管理的早期部分,但自首次实施以来,大部分 Django 代码都发生了变化,因此过去使用该包装器的方式有很多(即堆栈溢出 posts)已被弃用。我只是查看了源代码,并尝试了一些似乎合适的方法,直到它起作用为止。最后,这些文章帮了大忙:
我有一个 Django 3.x 网站。共有 3 个模型,其中 Document
、MetaData
、MetaDataValue
。 MetaDataValue
模型与 MetaData
模型有外键关系。
在一个简单的世界中,会有一个从MetaData
到Document
的外键关系。然后 DocumentAdmin
会将 MetaData
字段显示为下拉列表,其中填充了适当的 MetaDataValues
。下拉列表旁边还会有 edit/add (pencil/plus) 链接,以允许用户 edit/add 那个 MetaData
对象的 MetaDataValue
。
但是,该项目的要求之一是在 运行 之前不定义哪些或多少 MetaData
对象将与特定的 Document
类型相关联。这些关联是通过另一组模型实现的。因此,Document
管理更改页面在 运行 时将不同的 MetaData
字段添加到更改管理页面,方法是查看与此关联的 MetaData
字段的数据库Document
的类型,然后通过 get_fieldsets
方法将它们添加到字段集中。
这种设计的含义是不能 edit/add 值到 Document
管理更改页面上的特定 MetaData
字段,因为,我假设,Django 丢失了底层的外国Document
和 MetaData
模型之间的关键关系,因为字段集是在管理员的 get_fieldsets
方法中生成的。
我可以添加几页代码来显示 MetaData
字段是如何在 运行 时间生成的,但我认为这不会使描述更清楚。我已经查看了为上述“简单世界”示例生成的页面源和字段集,但看不到 Django 在哪里确定何时将 edit/change 链接添加到特定外键字段的下拉列表中。
我的问题是,如何将铅笔和加号添加到 Document
管理更改页面中显示的这些 MetaData
字段,并让用户选择 add/edit该特定 MetaData
对象的 MetaDataValue
?我可以只创建一些 Ajax 调用并自己完成所有繁重的工作,但我更愿意尽可能多地利用 Django 基础架构,而不是重新发明不必要的东西。
谢谢!
马克
我找到了使用 RelatedFieldWidgetWrapper
的解决方案。我将这个小部件包装器添加到我所有需要绿色加号(添加)和黄色铅笔(编辑)的选择中。
这里 post 的代码太多了,但这是它的核心。我的数据库 table MetaData
有所有字段的名称,MetaDataValue
有每个元数据字段的值。元数据用于描述文档(文本、视频、图像),但MetaData
模型和Document
模型之间没有FK关系。元数据和文档之间的关系包含在另一个 table 的 JSON 字段中。 MetaData
table 还具有用于该元数据字段的 Django 字段类型。还有另一个 table 确定哪些元数据字段适用于哪种文档类型(图像、文本、视频)。对于所有 ModelChoiceFields
,我添加了字段和小部件(Select
包装在 RelatedFieldWidgetWrapper
中)。
elif (metadata_names[i].field_type == MetaData.MODELCHOICEFIELD):
fields[metadata_names[i].name] = forms.ModelChoiceField(queryset=MetaDataValue.objects.filter(metadata_id=metadata_names[i].metadata_id).order_by('value'), required=False, label=metadata_names[i].label, help_text=metadata_names[i].help_text)
# add the green plus (add) and pencil (edit) links to each select field
fields[metadata_names[i].name].widget = RelatedFieldWidgetWrapper(fields[metadata_names[i].name].widget, MetaDataValue._meta.get_field('tag_value'), admin_site, can_add_related=True, can_change_related=True)
if 'documentType_id' in fields:
# Editing/add a new document type seems like a bad idea, as document type is used a lot in the processing logic
fields['documentType_id'].widget.can_add_related = False
fields['documentType_id'].widget.can_change_related = False
困难的部分是为 RelatedFieldWidgetWrapper
获取正确的参数。该小部件的文档有点稀疏,因为我认为它是管理的早期部分,但自首次实施以来,大部分 Django 代码都发生了变化,因此过去使用该包装器的方式有很多(即堆栈溢出 posts)已被弃用。我只是查看了源代码,并尝试了一些似乎合适的方法,直到它起作用为止。最后,这些文章帮了大忙: