Django+MongoDB创建模型时避免存储空值/Null属性
解决Djongo保存对象时去除None/null字段的问题
我之前用Django搭配Djongo连接MongoDB时,也碰到过完全一样的问题——默认情况下未传入的模型字段会被设为None,最后MongoDB里堆了一堆空值,特别浪费存储空间。毕竟MongoDB是文档型数据库,本来就该只存有实际值的字段。下面是我亲测有效的几种解决方案:
方案一:重写模型的save方法(推荐)
这是最直接的方式,在模型保存到数据库前自动过滤掉值为None的字段。步骤如下:
- 给需要设为可选的字段加上
null=True和blank=True(不然Django会因为字段不能为null抛出验证错误); - 重写模型的
save方法,遍历字段并删除值为None的属性。
修改后的models.py:
from djongo import models class MyClass(models.Model): _id = models.CharField(max_length=20, primary_key=True) attr1 = models.TextField(null=True, blank=True) attr2 = models.CharField(max_length=300, null=True, blank=True) attr3 = models.IntegerField(null=True, blank=True) attr4 = models.CharField(max_length=50, null=True, blank=True) def save(self, *args, **kwargs): # 收集所有值为None的字段名 fields_to_remove = [] for field in self._meta.fields: field_value = getattr(self, field.name) if field_value is None: fields_to_remove.append(field.name) # 删除这些字段,避免被保存到MongoDB for field_name in fields_to_remove: if hasattr(self, field_name): delattr(self, field_name) # 调用父类save方法完成保存 super().save(*args, **kwargs)
你原来的views.py代码完全不用改,创建实例时未传入的字段会被自动过滤,最终MongoDB里只会存储你传入的_id和attr1字段。
方案二:手动过滤数据后用raw_insert插入
如果不想修改模型,可以手动构建要保存的字典,过滤掉None值后直接用raw_insert插入数据库。这种方法会跳过Django ORM的字段默认值填充,直接操作MongoDB:
修改后的views.py:
def index(request): # 准备要保存的数据,只包含有值的字段 data = { '_id': 'TestID', 'attr1': 'Xxxx' } # 过滤掉值为None的键(如果有需要的话) filtered_data = {key: value for key, value in data.items() if value is not None} # 直接插入到MongoDB MyClass.objects.raw_insert([filtered_data])
注意:这个方法会跳过Django的模型验证,需要你自己确保数据符合字段规则(比如长度限制、类型匹配等)。
方案三:结合自定义管理器和save方法
如果希望创建对象时就自动过滤无效参数,可以自定义模型管理器,配合save方法一起使用:
from djongo import models class MyClassManager(models.Manager): def create(self, **kwargs): # 先过滤传入参数中值为None的键 filtered_kwargs = {k: v for k, v in kwargs.items() if v is not None} # 调用父类create方法创建实例 return super().create(**filtered_kwargs) class MyClass(models.Model): _id = models.CharField(max_length=20, primary_key=True) attr1 = models.TextField(null=True, blank=True) attr2 = models.CharField(max_length=300, null=True, blank=True) attr3 = models.IntegerField(null=True, blank=True) attr4 = models.CharField(max_length=50, null=True, blank=True) # 使用自定义管理器 objects = MyClassManager() # 同样需要重写save方法处理未传入的字段 def save(self, *args, **kwargs): fields_to_remove = [] for field in self._meta.fields: field_value = getattr(self, field.name) if field_value is None: fields_to_remove.append(field.name) for field_name in fields_to_remove: if hasattr(self, field_name): delattr(self, field_name) super().save(*args, **kwargs)
这样不管是用MyClass.objects.create()还是直接创建实例,都会自动过滤掉None值的字段,最终只存储有实际值的属性。
内容的提问来源于stack exchange,提问作者chopeds
相关产品推荐
相关产品推荐

