You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Djongo连接MongoDB时Django Admin嵌入字段报错求助

问题解决:Djongo EmbeddedField 在Django Admin中保存报错

报错原因

报错Value: gwalior-MP-India must be an instance of <class 'dict'>的核心问题是:Django Admin默认将City模型的__str__返回值(字符串格式的城市信息)作为city字段的提交值,但Djongo的EmbeddedField要求传入的是字典类型(对应MongoDB的嵌入文档)或者City模型实例,字符串类型不匹配导致保存失败。

解决方案

根据业务需求,分两种场景处理:

场景1:添加Address时直接输入新的城市信息

自定义Admin表单,为嵌入的City字段拆分成单独的输入框,提交时自动组装成EmbeddedField需要的字典格式:

修改admin.py:

from django.contrib import admin
from django import forms
from .models import City, Address

class CityAdmin(admin.ModelAdmin):
    list_display = ['city', 'state', 'country']

class AddressAdminForm(forms.ModelForm):
    # 拆分嵌入字段的输入项
    city_name = forms.CharField(max_length=255, required=False, label='城市')
    state_name = forms.CharField(max_length=255, required=False, label='省份/邦')
    country_name = forms.CharField(max_length=255, required=False, label='国家')

    class Meta:
        model = Address
        fields = ['city_name', 'state_name', 'country_name', 'pincode']

    def save(self, commit=True):
        instance = super().save(commit=False)
        # 将输入的城市信息组装成字典赋值给EmbeddedField
        if self.cleaned_data.get('city_name'):
            instance.city = {
                'city': self.cleaned_data['city_name'],
                'state': self.cleaned_data['state_name'],
                'country': self.cleaned_data['country_name']
            }
        if commit:
            instance.save()
        return instance

class AddressAdmin(admin.ModelAdmin):
    form = AddressAdminForm
    list_display = ['get_city', 'pincode']

    # 自定义列表页显示城市信息的方法
    def get_city(self, obj):
        if obj.city:
            return f"{obj.city.get('city')}-{obj.city.get('state')}-{obj.city.get('country')}"
        return '-'
    get_city.short_description = '城市信息'

admin.site.register(City, CityAdmin)
admin.site.register(Address, AddressAdmin)

场景2:选择已创建的City实例嵌入到Address中

如果希望复用已有的City数据,自定义表单让用户选择已创建的City,提交时将实例数据转换成字典:

修改admin.py:

from django.contrib import admin
from django import forms
from .models import City, Address

class CityAdmin(admin.ModelAdmin):
    list_display = ['city', 'state', 'country']

class AddressAdminForm(forms.ModelForm):
    # 添加下拉选择框选择已有City
    selected_city = forms.ModelChoiceField(queryset=City.objects.all(), required=False, label='选择已有城市')

    class Meta:
        model = Address
        fields = ['selected_city', 'pincode']

    def save(self, commit=True):
        instance = super().save(commit=False)
        # 将选中的City实例数据转换成字典
        if self.cleaned_data.get('selected_city'):
            city_obj = self.cleaned_data['selected_city']
            instance.city = {
                'city': city_obj.city,
                'state': city_obj.state,
                'country': city_obj.country
            }
        if commit:
            instance.save()
        return instance

class AddressAdmin(admin.ModelAdmin):
    form = AddressAdminForm
    list_display = ['get_city', 'pincode']

    def get_city(self, obj):
        if obj.city:
            return f"{obj.city.get('city')}-{obj.city.get('state')}-{obj.city.get('country')}"
        return '-'
    get_city.short_description = '城市信息'

admin.site.register(City, CityAdmin)
admin.site.register(Address, AddressAdmin)

补充说明

  • 原City模型中的_id字段可以保留,嵌入时无需手动传入,MongoDB会自动为嵌入文档生成_id(如果不需要可以删除该字段)。
  • 测试时先创建几个City实例,再操作Address的添加,即可正常保存数据。

内容的提问来源于stack exchange,提问作者Abhishek Jain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 17:15:39