Python django admin change list中的Custom list_可编辑字段,该字段不';t直接对应于模型字段

Python django admin change list中的Custom list_可编辑字段,该字段不';t直接对应于模型字段,python,django,django-admin,Python,Django,Django Admin,假设我的模型如下所示(这是一个简化的示例): 在管理更改列表中将名称显示为单个列非常简单。但是,我需要一个可编辑的“name”字段,该字段可以从列表页面编辑,然后我可以对其进行解析以提取和设置模型字段值。解析并不重要。我只是想知道如何在列表页面上有一个不直接对应于模型字段的可编辑表单字段 我刚刚在管理员界面上尝试了一个问题的快速模型。对于模型上未定义的可编辑列表中的字段,管理员验证似乎失败。简言之,你的问题的答案似乎是否定的 然而,这并不意味着它不可行。通过一点Javascript,您可以使用

假设我的模型如下所示(这是一个简化的示例):


在管理更改列表中将名称显示为单个列非常简单。但是,我需要一个可编辑的“name”字段,该字段可以从列表页面编辑,然后我可以对其进行解析以提取和设置模型字段值。解析并不重要。我只是想知道如何在列表页面上有一个不直接对应于模型字段的可编辑表单字段

我刚刚在管理员界面上尝试了一个问题的快速模型。对于模型上未定义的可编辑列表中的字段,管理员验证似乎失败。简言之,你的问题的答案似乎是否定的

然而,这并不意味着它不可行。通过一点Javascript,您可以使用


(或自己滚动),并使“名称”列可编辑。创建视图以验证数据并将其保存到模型中。设置X-可编辑字段“url”参数以发布到此url。显然,用login\u required/permissions\u required等装饰您的视图,以确保没有其他人可以编辑数据。

您应该能够在纯Python中通过一些工作来完成这项工作。基本上,您需要使用admin类上的方法来告诉它为您的实例使用自定义表单,而不是默认的
ModelForm
,然后正确初始化自定义字段的值(在表单的
\uuuu init\uuuu
方法中最方便)并专门化该表单的
save
行为,以设置
first\u name
last\u name

像这样的事情应该是一个开始:

class PersonChangeListForm(forms.ModelForm):
    class Meta:
        model = Person
    name = forms.CharField()

    def __init__(self, *args, **kwargs):
        instance = kwargs.get('instance')
        if instance:
            initial = kwargs.get('initial', {})
            initial['name'] = '%s %s' % (instance.first_name, instance.last_name)
            kwargs['initial'] = initial
        super(PersonChangeListForm, self).__init__(*args, **kwargs)

    def save(self, *args, **kwargs):
        # use whatever parsing you like here
        first_name, last_name = self.cleaned_data['name'].split(None, 1)
        self.cleaned_data['first_name'] = first_name
        self.cleaned_data['last_name'] = last_name
        return super(PersonChangeListForm, self).save(*args, **kwargs)

class PersonAdmin(admin.ModelAdmin):
    def get_changelist_form(self, request, **kwargs):
        return PersonChangeListForm
您还需要声明一个
list\u editable
值,当作为布尔值进行测试时,该值的计算结果为
True
——如果
list\u editable
的计算结果不为
True
,则一些管理员在不使用表单集的情况下处理短路

如果没有其他要编辑的字段,这会变得更复杂。类验证要求
list\u editable
序列中的所有内容都是在
list\u display
中声明的可编辑字段,而不是显示链接字段。我认为有两种选择,一种是覆盖admin类的
changelist\u视图
方法,即使
list\u editable
不为真,也可以使用完整的处理,另一种是定义
list
tuple
的自定义子类,即使在为空时也可以计算为
true
,以便通过验证。前者需要重复大量的标准代码,如果你升级的话,会大大增加你的维护负担,而后者是一种违反直觉的黑客行为,如果它产生了意想不到的后果,我一点也不会感到惊讶


两者都不是好的选择,因此我希望您至少有一个其他字段可以包含在@Peter DeGlopper答案中的
列表可编辑
中。您可以在
列表可编辑
中添加其他模型字段(例如
姓氏
),然后覆盖
更改列表.html
(查看此答案,并在文件末尾添加一些javascrip代码: 模板/admin/your_app/person/change_list.html

{% extends "admin/base_site.html" %}
{% load i18n admin_urls static admin_list %}
...

{% block content %}
...
{% endblock %}

{% block footer %}
{{ block.super }}
<script>
    var last_names = document.querySelectorAll('.field-last_name');

    last_names.forEach(function(el) {
        var input = el.children[0];
        var text = input.value;
        input.hidden = true;
        input.style.display = 'none';
        el.append(text);
    });
</script>
{% endblock %}
{%extends“admin/base\u site.html”%}
{%load i18n admin_URL静态admin_list%}
...
{%block content%}
...
{%endblock%}
{%block footer%}
{{block.super}}
var last_name=document.querySelectorAll('.field-last_name');
姓氏。forEach(函数(el){
变量输入=el.children[0];
var text=input.value;
input.hidden=true;
input.style.display='none';
el.追加(文本);
});
{%endblock%}

谢谢Peter,看起来很有希望。我会检查一下。这肯定让我走上了正确的轨道…我不得不在列表可编辑字段中使用一个实际的模型字段列(即“第一个”字段),只是将显示名称更改为“全名”然后使用init和save方法实际解析出值并保存它们。据我所知,我无法在列表页面中将非模型表单字段显示为列。但它成功了。谢谢!嘿,希望你看到我的评论。我使用了你的方法,但我无法管理
列表可编辑
工作,Django demands认为列表中的所有内容都必须是模型字段,所以我无法说服它使用表单字段,所以这种方法对我来说失败了。你知道我做错了什么吗?@Andrey-我已经有一段时间没有看它了,但如果我正确地回忆起自定义表单字段(
name
,在上面的示例中)不需要在
列表\u editable
中。你只需要在那里有一些东西,Django就可以创建表单集。我回答的最后两段是我最好的选择,如果你没有想要编辑的模型字段,只有自定义字段。@Ben Roberts,我按照你的方法,它可以显示可编辑字段“name”在更改列表中,我更改了“名称”字段值并单击“保存”按钮,Django没有将我的编辑保存到“名称”字段。我运行调试,发现PersonChangeListForm(forms.ModelForm)类中的函数save(self,*args,**kwargs)没有被调用。
{% extends "admin/base_site.html" %}
{% load i18n admin_urls static admin_list %}
...

{% block content %}
...
{% endblock %}

{% block footer %}
{{ block.super }}
<script>
    var last_names = document.querySelectorAll('.field-last_name');

    last_names.forEach(function(el) {
        var input = el.children[0];
        var text = input.value;
        input.hidden = true;
        input.style.display = 'none';
        el.append(text);
    });
</script>
{% endblock %}