使用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
相关产品推荐
相关产品推荐

