在迭代查询集中将参数传递给对象模型类的__init__

时间:2017-09-01 07:50:42

标签: django django-models django-queryset

我有一个带有重写__init__方法的模型,如下所示:

class MyModel(models.Model):
    ...

    def __init__(self, *args, **kwargs):
        if not kwargs.get('skip', False):
            do_something()
        super().__init__(*args, **kwargs) 

当我查询集时,如何将skip参数传递给__init__

data = [obj for obj in MyModel.objects.all()]

我想在自定义管理器中实现此方法,使用以下内容:queryset.with_skip()

1 个答案:

答案 0 :(得分:2)

我发现,在将let a = NSAlert() a.messageText = "Dummy1" a.informativeText = "Dummy2" a.addButton(withTitle: "OK") let rb = NSButton(radioButtonWithTitle: "Foo", target: nil, action: nil) let vsv = NSStackView() vsv.orientation = NSUserInterfaceLayoutOrientation.vertical vsv.distribution = NSStackViewDistribution.equalSpacing vsv.alignment = .leading vsv.isHidden = false vsv.addView(rb, in: .center) a.accessoryView = vsv a.runModal() 传递给skip之前,您不会从kwargs删除参数super().__init__。这意味着"跳过"是字段的名称,否则您会遇到异常TypeError("'skip' is an invalid keyword argument for this function")

如果在创建对象之前确实需要do_something(),那么在使用之前必须忘记避免所有不支持的方式(??),那么自定义管理器等是不够的。

您的问题是,models.Model.__init__(...)完全支持*args**kwargs参数,因此它们应该是可互换的。你打破了它,如果"跳过"由位置参数的完整元组传递,你忽略它。也就是说,如果对象是从数据库创建的。阅读文档Customizing model loading

  

...如果所有模型的字段都存在,那么值保证按__init__()期望的顺序排列。也就是说,可以通过cls(*values) ...来创建实例   。
  | @classmethod
  | def from_db(cls, db, field_names, values):
  | ...
  | instance = cls(*values)
  | ...

一种简单的解决方法是在do_something()之后调用super().__init__并阅读self.skip,而不是实现解析kwargs和args。

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs) 
        if not self.skip:
            do_something()

问题可能是信号" post_init"如果您需要,可以在super().__init__结束时发送。

最后一种可能性是支持*args(hacky,但仍然使用文档化名称):

    def __init__(self, *args, **kwargs):
        if kwargs:
            skip = kwargs.get('skip', False)
        else:
            # check "val is True" in order to skip if val is DEFERRED
            skip = any(field.name == 'skip' and val is True
                       for val, field in zip(args, self._meta.concrete_fields)
                       )
        if not skip:
            do_something()
        super().__init__(*args, **kwargs)

编辑:也许你不需要你想要的东西和一个Proxy model,它可以在同一个数据库表中的相同数据的基本模型上做一些额外的事情是正确的解决方案。 (" Skip"看起来不像是描述对象数据的名称,而是描述对象创建模式的名称。测试和维护子类比内部神秘的开关更容易。)