2016-07-01 3 views
6

양식 필드와는 달리 모델 필드에 일반 mixin을 만들려고하는데 mixin의 init은 명명 된 인수를 사용합니다. 믹스 인을 다른 클래스와 함께 인스턴스화하는 데 어려움이 있습니다.django 모델 필드 mixin 만드는 방법

<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 번 실행 : 여기

는 다음과 같은 출력을 생산하고이 모델에 대한 마이그레이션을 만들기 코드

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

입니까? 두 번째 부분에서 kwarg 'new_arg'는 어디에 있습니까? 장고에 대해 필드 믹스를 만드는 방법은 무엇입니까?

편집 : another question 달리,이 질문에 대한 필드를 유지 mixin을 요청 , 링크 된 질문 모델 유지 mixin을 의미합니다.

+0

어떤 버전의 django를 사용하고 있습니까? – Aya

+0

버전 1.9를 사용 중입니다. – jmerkow

+0

@solarissmoke 같은 질문이 아닙니다. –

답변

2

첫째, 왜 3 번을 실행 init이있다? 한 번만 수입 된 models.py 비록

, 같은 내부 만든 Field 객체 ...

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

는 ... 키워드 인수를 사용하여 필드 생성자를 호출 포함하는 여러 번 복제된다 그들은 원래로 창조되었다. 당신은

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

어디 ...이 일어나는 곳을보고 출력에 다음과 같은 여러 번 표시

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

를 ... ... traceback 모듈을 사용할 수 있습니다 두 번째 둘의 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 매개 변수는 생성자에 전달되지 않습니다.

그러나, 슈퍼 클래스 생성자에 해당 옵션을 건네 주면 ...


어떻게

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' 
CharField 그 키워드 인수를 지원하지 않기 때문에, 작동하지 않습니다, 그래서 당신은 얻을 것이다 내가 장고에 대한 필드 mixin 만들려면 어떻게합니까?

사용자 정의 필드 옵션을 추가하려면이 복제 행동, 당신은 장고 새 옵션을 직렬화 할 수 있도록 사용자 정의 deconstruct() 방법을 정의 할 필요가 있기 때문에

...

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 
+0

나는 나의 대답에서 나의 모든 질문에 대답하지 않았다. 그래서 너를 받아 들일거야. – jmerkow

+0

빠른 질문, 내 대답은 모델에서 MyMixin을 상속받습니다. 필드, 영향을 줍니까? – jmerkow

+0

@jmerkow'Model'에서 메타 클래스를 사용하기 때문에 명확하게 대답하는 것이 특히 빠른 질문이 아닙니다. 'MyMixin'가'Field'를 직접 하위 클래스로 묶는 경우, 어떤 상황에서는'Field'에 정의 된 함수를 덮어 쓰는'CharField' 함수가 무시되어 잘못된 함수를 호출하게됩니다. 아마 그 가능성을 피하는 것이 더 안전 할 것이고, 단지'myMixin' 하위 클래스 인'object'를 가질 것입니다. 이것은 mixin이 어쨌든해야 할 일입니다. – Aya

1

그래서 제멋대로하고 다시 읽은 다음에 알아 냈습니다. django docs on custom model fields init과 함께 deconstructor가 필요합니다. Django 필드는 deconstruct 메서드를 직렬화해야합니다.

믹스 인뿐만 아니라이 방법이 있어야합니다

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 
+0

게시했을 때 좀 더 자세한 답변을 거의 다 작성했습니다. :) – Aya