如何创建一个django模型字段mixin

jme*_*kow 6 python django

我正在尝试为模型字段(而不是表单字段)创建通用mixin,mixin的init采用命名参数.我遇到麻烦用另一个类实例化mixin.

这是代码

class MyMixin(object):
    def __init__(self, new_arg=None, *args, **kwargs):
        super(MyMixin, self).__init__(*args, **kwargs)
        print self.__class__, new_arg


class MyMixinCharField(MyMixin, models.CharField):
    pass

...

class MyMixinModelTest(models.Model):
    myfield = MyMixinCharField(max_length=512,new_arg="myarg")
Run Code Online (Sandbox Code Playgroud)

对此模型进行迁移会产生以下输出:

<class 'myapp.mixintest.fields.MyMixinCharField'> myarg 
<class 'myapp.mixintest.fields.MyMixinCharField'> None 
<class 'myapp.mixintest.fields.MyMixinCharField'> None 
Migrations for 'mixintest':   
   0001_initial.py:
        - Create model MyMixinModelTest
Run Code Online (Sandbox Code Playgroud)

首先,为什么init运行3次?在第二个两个中,kwarg'new_arg'在哪里?如何为django创建字段mixin?

编辑:与另一个问题相反,这个问题询问混合,相关问题是指模型混合.

Aya*_*Aya 5

首先,为什么init运行了3次?

虽然models.py只导入一次,但Field其中创建的对象,例如...

myfield = MyMixinCharField(max_length=512, new_arg="myarg")
Run Code Online (Sandbox Code Playgroud)

...被克隆多次,其中涉及使用最初创建它们的关键字 args 调用字段构造函数。您可以使用该traceback模块来查看它发生在哪里......

import traceback

class MyMixin(object):
    def __init__(self, new_arg=None, *args, **kwargs):
        super(MyMixin, self).__init__(*args, **kwargs)
        print self.__class__, new_arg
        traceback.print_stack()
Run Code Online (Sandbox Code Playgroud)

...在输出中多次显示以下内容...

  File "django/db/migrations/state.py", line 393, in from_model
    fields.append((name, field.clone()))
  File "django/db/models/fields/__init__.py", line 464, in clone
    return self.__class__(*args, **kwargs)
  File "myproj/myapp/models.py", line 11, in __init__
    traceback.print_stack()
Run Code Online (Sandbox Code Playgroud)

后两个中的 kwarg 'new_arg' 在哪里?

当你最初打电话...

myfield = MyMixinCharField(max_length=512, new_arg="myarg")
Run Code Online (Sandbox Code Playgroud)

..."myarg"作为参数传递给new_arg...

def __init__(self, new_arg=None, *args, **kwargs):
Run Code Online (Sandbox Code Playgroud)

...但是因为您没有将该参数传递给底层Field构造函数...

super(MyMixin, self).__init__(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

...它没有存储在底层的任何地方Field对象中的任何位置,因此当克隆字段时,new_arg参数不会传递给构造函数。

但是,将该选项传递给超类构造函数将不起作用,因为不CharField支持该关键字 arg,所以您会得到...

  File "myproj/myapp/models.py", line 29, in MyMixinModelTest
    myfield = MyMixinCharField(max_length=512, new_arg="myarg")
  File "myproj/myapp/models.py", line 25, in __init__
    super(MyMixinCharField, self).__init__(*args, **kwargs)
  File "django/db/models/fields/__init__.py", line 1072, in __init__
    super(CharField, self).__init__(*args, **kwargs)
TypeError: __init__() got an unexpected keyword argument 'new_arg'
Run Code Online (Sandbox Code Playgroud)

如何为 django 创建字段 mixin?

由于这种克隆行为,如果您想添加自定义字段选项,则必须定义一个自定义deconstruct()方法,以便 Django 可以序列化您的新选项...

class MyMixin(object):
    def __init__(self, new_arg=None, *args, **kwargs):
        super(MyMixin, self).__init__(*args, **kwargs)
        self.new_arg = new_arg
        print self.__class__, new_arg

    def deconstruct(self):
        name, path, args, kwargs = super(MyMixin, self).deconstruct()
        kwargs['new_arg'] = self.new_arg
        return name, path, args, kwargs


class MyMixinCharField(MyMixin, models.CharField):
    pass


class MyMixinModelTest(models.Model):
    myfield = MyMixinCharField(max_length=512, new_arg="myarg")
Run Code Online (Sandbox Code Playgroud)

...输出...

<class 'myapp.models.MyMixinCharField'> myarg
<class 'myapp.models.MyMixinCharField'> myarg
<class 'myapp.models.MyMixinCharField'> myarg
Run Code Online (Sandbox Code Playgroud)