首页 > 解决方案 > 如何在管理中间页面中重用 Django 的管理外键小部件

问题描述

我无法在 Django 文档的任何地方找到答案。不过,我并不感到惊讶,因为这个问题有点过于复杂,无法向搜索引擎提问。

我的情况是,我需要能够ForeignKey为 Django 管理站点上的一个或多个模型条目重新分配一个字段。

到目前为止,我尝试使用自定义操作来执行此操作,以便我可以选择我感兴趣的记录并一次修改它们。但是,然后,我需要选择我希望将其 fk 重新分配给的新相关对象。所以,我想做的是一个中间页面,我会在其中显示我在管理页面周围看到的 fk 小部件:

在此处输入图像描述

但事实证明,这个小部件真的不是为公开使用而设计的。它没有记录,使用起来非常复杂。到目前为止,我花了几个小时来研究 Django 的代码,试图弄清楚如何使用它。

我觉得我正在尝试在这里做一些非常奇特的事情,所以,如果有其他解决方案,我都会听到。

标签: djangodjango-admin

解决方案


正如shahbaz ahmad建议的那样,您可以使用ModelAdmin'sautocomplete_fields来创建select带有自动补全功能的。

但是如果你被 Django 的外键小部件卡住了,例如,因为你有看起来相同并且在自动完成中无法区分的记录,那么有一个解决方案。

事实证明,您可以使用ModelAdmin一种get_form方法来检索ModelForm管理页面上使用的内容。此方法接受一个fieldskwargs,您可以使用它来选择要在表单中检索的字段。像这样使用它:

class MyAdmin(ModelAdmin):
    # define the admin subpath to your intermediate page
    def get_urls(self):
        return [
            path(
                "intermediate_page/",
                self.admin_site.admin_view(self.intermediate_page),
                name="intermediate_page",
            ),
            *super().get_urls(),
        ]

    def intermediate_page(self, request):
        context = {
            # The rest of the context from admin
            **self.admin_site.each_context(request),
            # Retrieve the admin form
            "form": self.get_form(
                request,
                fields=[], # the fields you're interested in
            )
        }

        return render(request, "admin/intermediate_page.html", context)

如果您的字段是只读的 - 这是我的情况 - 有一个可编辑字段的解决方法:您可以覆盖get_readonly_fieldsget_form.

此方法接受一个obj参数,该参数通常采用正在编辑的对象的模型或None创建新条目时。您可以劫持此参数以强制get_readonly_fields从只读字段中排除字段:

def get_readonly_fields(self, request, obj=None):
    readony_fields = super().get_readonly_fields(request, obj)
    if not (
        isinstance(obj, dict)
        and isinstance(obj.get("exclude_from_readonly_fields"), Collection)
    ):
        return readony_fields

    return set(readony_fields) - set(obj["exclude_from_readonly_fields"])

get_form它还具有obj传递给的此参数,get_readonly_fields因此您可以像这样调用它:

# the fields you're interested in
include_fields = []

self.get_form(
    request,
    obj={"exclude_from_readonly_fields": include_fields},
    fields=include_fields
)

推荐阅读