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

Ron*_*Arr 5 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) 
Run Code Online (Sandbox Code Playgroud)

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

data = [obj for obj in MyModel.objects.all()]
Run Code Online (Sandbox Code Playgroud)

我想在自定义管理器中通过方法实现这个,使用这样的东西: queryset.with_skip()

hyn*_*cer 2

skip我发现您在将参数kwargs传递给 之前没有删除参数super().__init__。这意味着“skip”是字段的名称,否则会出现异常TypeError("\'skip\' is an invalid keyword argument for this function")

\n\n

如果您确实需要do_something()在使用之前创建对象时如此不可或缺,以至于没有人应该忘记避免所有不受支持的方式(??),那么自定义管理器等还不够。

\n\n

你的问题是,它完美地models.Model.__init__(...)支持了*args**kwargs参数,以至于它们应该可以互换。您破坏了它,如果“跳过”由位置参数的完整元组传递,您将忽略它。也就是说,如果该对象是从数据库创建的。阅读文档自定义模型加载

\n\n
\n

...如果所有 model\xe2\x80\x99s 字段都存在,则保证值按照预期的顺序排列__init__()。也就是说,实例可以通过cls(*values)...
\n 创建。
\n | @classmethod
\n | def from_db(cls, db, field_names, values):
\n | ...
\n | instance = cls(*values)
\n | ...

\n
\n\n

解决这个问题的一个简单方法是调用do_something()aftersuper().__init__和 readself.skip而不是实现解析 kwargs 和 args。

\n\n
    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs) \n        if not self.skip:\n            do_something()\n
Run Code Online (Sandbox Code Playgroud)\n\n

super().__init__如果您需要的话,问题可能是在末尾发送的信号“post_init” 。

\n\n

最后一种可能性是支持*args(hacky,但仍然以某种方式使用记录的名称):

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

编辑:也许您不需要您想要的东西,代理模型有时可以在同一数据库表中的相同数据上对基本模型执行额外的操作,这是正确的解决方案。(“Skip”看起来不像是描述对象数据的名称,而是像描述对象创建模式的名称。测试和维护子类比内部神秘的开关更容易。)

\n