Django - 修改的管理表单返回对象而非文本

1 投票
2 回答
34 浏览
提问于 2025-04-14 18:17

我正在尝试在一个Django网站上自定义一个管理员表单,希望把其中一个字段从文本框改成一个下拉选择框,这个下拉框的选项是从一个地点表中获取的所有序列号(每个地点都有一个独特的编号)。

这是表单的代码:

class SglnModelChoiceField(ModelChoiceField):
    def label_from_instance(self, obj):
        return obj.sgln + ":" + obj.name

class EndpointForm(forms.ModelForm): 
    sgln = SglnModelChoiceField(
        queryset=Location.objects.all(),
        to_field_name="sgln",
        label="Endpoint SGLN",
        required=True,
    )
    login = forms.CharField(label='Endpoint Login', max_length=32, required=True)
    password = forms.CharField(label='Endpoint Password', max_length=32, required=True)

这是管理员的代码:


from django.contrib import admin
from .forms import EndpointForm
from .models import Endpoints

class EndpointAdmin(admin.ModelAdmin):
    form = EndpointForm

admin.site.register(Endpoints, EndpointAdmin)

表单看起来不错:

Django管理员表单

HTML也看起来不错:

[HTML picture] (https://i.stack.imgur.com/n4eqG.png)

但是数据库中显示插入了一个“object(1)”的内容,和其他字段一起。这应该是从下拉框中选出的序列号。

数据库行

有没有人能给点提示,为什么会这样?

更新 - 为了更清楚,我添加了一个简化的地点模型(不需要所有字段)和端点模型,但它们都是标准模型。

这是模型的代码:

class Location(models.Model):
        sgln = models.CharField(max_length=15, unique=True)
        name = models.CharField(max_length=64)
        streetAddress = models.CharField(max_length=64)
        suite = models.CharField(max_length=64)
        city = models.CharField(max_length=32)
        state = models.CharField(max_length=2)
        postalCode = models.CharField(max_length=10)
    
class Endpoints(models.Model):
        sgln = models.CharField(max_length=19, unique=True)
        login = models.CharField('Endpoint Login ', max_length=32, default=None, null=True)
        password = models.CharField('Endpoint Password', max_length=32, default=None, null=True)
        tstamp = models.DateTimeField(auto_now_add=True)

2 个回答

1

问题在于你使用了一个 ModelChoiceField 来选择一个 CharField 的值。当你提交数据到 ModelChoiceField 时,它会把这个值转换成指定的模型实例。这种字段是用来处理模型中的外键的,而不是用在 CharField 上。对于你的情况,你应该使用一个 ChoiceField

def get_sgln_choices():
    return [
        (location["sgln"], location["sgln"] + ":" + location["name"])
        for location in Location.objects.values("sgln", "name")
    ]

class EndpointForm(forms.ModelForm):
    sgln = ChoiceField(
        choices=get_sgln_choices
        label="Endpoint SGLN",
        required=True,
    )
0

第三张图片(数据库那张)来源不太明显,但Class object (id)是Django默认用来表示模型实例的格式。

如果你想改变这个格式,可以重写你的Model类中的__str__方法。

举个例子,你的Location类可以这样写:

class Location(models.Model):
    # Some fields including sgln and name

    def __str__(self):
        return self.sgln + ":" + self.name

现在,如果你尝试打印一个Location模型的实例,它会显示self.sgln + ":" + self.name的结果,而不是Location object (<id>)

撰写回答