簡體   English   中英

如何創建一個django模型字段mixin

[英]How to create a django model field mixin

我正在嘗試為模型字段(而不是表單字段)創建通用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")

對此模型進行遷移會產生以下輸出:

<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

首先,為什么init運行3次? 在第二個兩個中,kwarg'new_arg'在哪里? 如何為django創建字段mixin?

編輯:與另一個問題相反,這個問題詢問混合,相關問題是指模型混合。

首先,為什么init運行3次?

雖然models.py只導入一次,但是在其中創建了Field對象,例如......

myfield = MyMixinCharField(max_length=512, new_arg="myarg")

...多次克隆,包括使用最初創建的關鍵字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()

...在輸出中顯示以下幾次...

  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()

在第二個兩個中,kwarg'new_arg'在哪里?

當你最初打電話給...

myfield = MyMixinCharField(max_length=512, new_arg="myarg")

... "myarg"作為new_arg參數傳遞給...

def __init__(self, new_arg=None, *args, **kwargs):

...但是因為你沒有將該參數傳遞給基礎的Field構造函數...

super(MyMixin, self).__init__(*args, **kwargs)

...它沒有存儲在底層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'

如何為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")

...輸出......

<class 'myapp.models.MyMixinCharField'> myarg
<class 'myapp.models.MyMixinCharField'> myarg
<class 'myapp.models.MyMixinCharField'> myarg

所以我經過大量的修補和重新閱讀自定義模型字段上django文檔后想出來你需要一個解構函數和你的init。 Django字段需要一個deconstruct方法來序列化。

mixin也應該有這個方法:

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

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM