Django在构建模型时忽略额外的参数。

7

我有一个小的Django项目,从外部源获取一些信息并使用它来构建模型实例。问题是,该源返回了许多(而且我是指很多!)我不需要的额外信息。

目前,我必须找出其中的额外记录,并手动逐个删除。但这不太好,因为

  1. It makes for very ugly code and
  2. If the external source changes, e.g. it adds a new field, my code will throw an error when I construct a model

    myModel = MyModel(**argDict)
    
有没有一种方法可以将过度完整的argDict传递给我的模型,并使其抑制有关额外信息的任何错误,并且只是丢弃它?我想我可以使用pre_init信号,但我仍然不知道如何停止返回该错误。
3个回答

9

meta API 通过 get_fields() 提供了所有可用字段实例的列表。您可以编写一个实用函数来过滤 init 的 kwargs。

def init_kwargs(model, arg_dict):
    model_fields = [f.name for f in model._meta.get_fields()]
    return {k: v for k, v in arg_dict.items() if k in model_fields}

然后,
kwars = init_kwargs(myModel, arg_dict)
myModel = MyModel(**kwargs)

适用于所有型号。

使用元 API 是个好主意,但我会避免覆盖模型的 __init__ 方法。一些替代方案包括定义一个函数,例如 create_model_from_external_data(**argDict) 或者一个管理方法,例如 MyModel.objects.create_from_external_data(**argDict) - Alasdair
1
Django文档鼓励使用替代方案来覆盖__init__。在这种情况下,我认为最好调用一个方法,明确表明您正在丢弃数据,而不是在应用程序的各个地方更改行为,这可能会隐藏微妙的错误。 - Alasdair
1
@Alasdair 我必须同意。客户端可能依赖于引发超出需求的kwargs的错误,而覆盖__init__会改变该行为。编辑了我的答案,感谢澄清! - user2390182
@JMzance 不需要,你可以在项目的某个常用函数中实现。如果将其作为 myModel 的类方法,则会降低其可重用性(因为你需要将 model 参数替换为 cls)。 - user2390182
3
对于Python3:将arg_dict.iteritems()替换为arg_dict.items()。 - mighty_mike
显示剩余3条评论

2
创建一个不带任何参数的空实例。然后使用setattr设置值。对于模型上不存在的字段,您不应该收到任何错误提示。
my_model = MyModel()
for key, value in argDict.items():
    setattr(my_model, key, value)
my_model.save()

你可以将上述代码封装在一个函数中以便重复使用,或许作为自定义管理器的一个方法。

1

我需要修改被接受的答案才能使其正常工作(Python 3.6.3):

def init_kwargs(model, arg_dict):
return {
    k: v for k, v in arg_dict.items() if k in [
       f.name for f in model._meta.get_fields()
    ]
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接