使用Djongo的EmbeddedField失败,报错:Value: en必须是dict实例
解决Djongo EmbeddedField报错:Value: en must be an instance of <class 'dict'>
这个报错的核心原因很明确:Djongo的EmbeddedField要求接收一个字典(对应MongoDB的嵌入文档),但你在Django Admin中提交的数据没有被正确封装成字典,反而直接传递了code字段的字符串值(比如'en')。下面是分步解决方法:
1. 先修复Campaign模型的小问题
你的Campaign模型的__str__方法引用了self.name,但模型里并没有定义name字段,这会引发额外错误,先修正它:
class Campaign(models.Model): _id = models.ObjectIdField() language = models.EmbeddedField(model_container=Language, model_form_class=LanguageForm) objects = models.DjongoManager() def __str__(self): return f'{self.language.code}' # 改为引用language的code字段
2. 自定义Django Admin类,正确处理EmbeddedField数据
Django Admin默认不会自动将嵌入模型的字段封装成字典,我们需要自定义Admin类来手动处理这一步:
from django.contrib import admin from .models import Campaign class CampaignAdmin(admin.ModelAdmin): def save_model(self, request, obj, form, change): # 从表单中提取语言相关字段,封装成EmbeddedField需要的字典结构 lang_data = { 'code': form.cleaned_data.get('language-code'), 'direction': form.cleaned_data.get('language-direction') } obj.language = lang_data super().save_model(request, obj, form, change) # 重写get_form方法,让Admin显示嵌入模型的子字段(而不是一个单独的表单组件) def get_form(self, request, obj=None, **kwargs): form = super().get_form(request, obj, **kwargs) # 将EmbeddedField的子字段单独提取到表单中 lang_form_fields = form.base_fields.pop('language').fields form.base_fields['language-code'] = lang_form_fields['code'] form.base_fields['language-direction'] = lang_form_fields['direction'] return form # 注册自定义的Admin类 admin.site.register(Campaign, CampaignAdmin)
3. 验证数据结构(可选)
如果你用Django Shell测试创建数据,一定要确保传递的是字典格式,而不是单个字符串:
# 正确的创建方式 Campaign.objects.create(language={'code': 'en', 'direction': 'ltr'}) # 错误的方式(会触发你遇到的报错) Campaign.objects.create(language='en')
补充说明
你当前的环境配置(Django2.2.16 + Djongo master分支 + Python3.6 + MongoDB3.6)是兼容的,不需要调整依赖版本,主要问题出在Admin表单对EmbeddedField的默认处理逻辑上。
内容的提问来源于stack exchange,提问作者Bruno Wego
相关产品推荐
相关产品推荐

