将Django ModelChoiceField更改为显示用户的全名而不是用户名

38

我在Django应用程序中有一个表单(不是在管理界面),它允许工作人员从下拉菜单中选择用户。

forms.ModelChoiceField(queryset = User.objects.filter(is_staff=False), required = False)

问题在于下拉菜单是按用户名显示用户,而我希望它从user.get_full_name()中显示他们的全名,并且仅在不可用时使用用户名。我只需要在这个页面上进行这个更改,在其他地方如管理员界面,如果使用用户名我并不介意。

有没有办法可以做到这一点呢?

谢谢!

5个回答

83

您可以设置自定义的 ModelChoiceField,以返回您想要的任何标签。

在 fields.py 或其他适用位置中放置类似以下内容的代码:

class UserModelChoiceField(ModelChoiceField):
    def label_from_instance(self, obj):
         return obj.get_full_name()

然后,在创建表单时,只需使用该字段即可。

 UserModelChoiceField(queryset=User.objects.filter(is_staff=False), required = False)

更多信息可以在这里找到。


谢谢!那个可行,但它不是forms.UserModelChoiceField,而是你放置那个类的位置。UserModelChoiceField - Adam
这对我没用,我收到了错误NameError:name'UserModelChoiceField'未定义。我将其放在定义类UserModelChoiceField之后。我还需要做其他事情吗,比如注册类或其他什么吗?(我正在尝试在管理界面中完成此操作。) - David Rhoden
感谢您提供的解决方案,在2022年,祝您新年快乐。 - Dinesh Chandra Kumawat

36

在使用ModelForm时,我发现以下方法非常有用,因为我不需要重新定义我的queryset——特别是因为我在模型定义中使用了limit_choices_to:

class MyModelForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(MyModelForm, self).__init__(*args, **kwargs)
        self.fields['user'].label_from_instance = lambda obj: "%s" % obj.get_full_name()

根据这个答案进行定制 https://dev59.com/3mw15IYBdhLWcg3wFHzf#7805824


1
运行得非常好! - jsanchezs
可能出现错误:'ModelForm未指定模型类'. 需要将class MyModelForm(forms.ModelForm)替换为class MyModelForm(forms.Form). - Kirill Vladi

2

2
如果您想在模型表单中更改字段的选项,请尝试使用Bartek答案的这种适应方法:
模型:
class MyModel(models.Model)
    user = models.ForeignKey(...)

表单字段:

class UserModelChoiceField(forms.ModelChoiceField):
    def label_from_instance(self, obj):
        return obj.get_full_name()

表单:

class MyModelForm(forms.ModelForm):
    class Meta:
        model = MyModel
        fields = ['user']
        field_classes = {
            'user': UserModelChoiceField
        }

这种方法将保留字段的参数(您不需要指定querysetrequired等)。

0

你也可以创建一个自定义的ModelChoiceField,并将函数传递给它。这样,如果你有不同的字段需要显示不同的属性,你只需要使用一个类:

class CustomModelChoiceField(forms.ModelChoiceField):
name_function = staticmethod(lambda obj: obj)

def __init__(self, name_function, *args, **kwargs):
    if not name_function is None: self.name_function = name_function
    super(CustomModelChoiceField, self).__init__(*args, **kwargs)

def label_from_instance(self, obj):
     return self.name_function(obj);

你可以简单地这样调用它:
form_field = CustomModelChoiceField(
    lambda obj: obj.get_full_name(),
    queryset=Whatever.objects.all(),
)

如果你正在进行一些动态操作,你也可以传递None,它将基本上默认为常规的ModelChoiceField。虽然我不是太懂Python,但这对我很有效。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接