2012-04-13 95 views
0

這可能更像是一個面向對象的Python問題。但它來自this question我問到關於Django。如何將變量傳遞給Python/Django中的繼承類?

所以@burhan告知,而不是手工寫出我的自定義<select>和我的Django的模板中<option>標籤,我應該只使用一個定製ModelChoiceFieldforms.Select

我目前的繼承ModelForm,創造我的模型Order稱爲OrderCreateForm自定義窗體中,creatorqueryset是基於什麼creatoruser_type是,因此我需要一個變量某種方式傳遞到自定義ModelForm是用於定製ModelChoiceField

所以我最終想要的東西,這樣的

class OrderCreateForm(ModelForm): 
    class Meta : 
     model=Order 
     fields=('work_type', 'comment',) 

    def __init__(self): 
     # somehow get a variable called user_type 

    if user_type == 'foo': 
     queryset = User.objects.all() 
    else: 
     queryset = User.objects.filter(userprofle__user_type='bar') 

    creator = MyCustomField(queryset=queryset, 
          empty_label="Please select", 
          widget=forms.Select(attrs={'onchange':'some_ajax_function()'}) 

我知道在一個類來創建參數有事情做與__init__,但我是一個新手,OO,如果創造我自己的,我不知道__init__將與ModelForm.__init__衝突。此外,我想打電話給我的自定義ModelForm類如form=OrderCreateForm(user_type='foo_bar')。這是可能的。

對不起,如果我的問題很混亂,就像我說我是一個OO新手,我不知道所有的術語和概念都很好。

編輯:下面是來自Django的關於ModelForm一些源代碼:

class BaseForm(StrAndUnicode): 
    # This is the main implementation of all the Form logic. Note that this 
    # class is different than Form. See the comments by the Form class for more 
    # information. Any improvements to the form API should be made to *this* 
    # class, not to the Form class. 
    def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, 
       initial=None, error_class=ErrorList, label_suffix=':', 
       empty_permitted=False): 

class BaseModelForm(BaseForm): 
    def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, 
       initial=None, error_class=ErrorList, label_suffix=':', 
       empty_permitted=False, instance=None): 
     opts = self._meta 
     if instance is None: 
      if opts.model is None: 
       raise ValueError('ModelForm has no model class specified.') 
      # if we didn't get an instance, instantiate a new one 
      self.instance = opts.model() 
      object_data = {} 
     else: 
      self.instance = instance 
      object_data = model_to_dict(instance, opts.fields, opts.exclude) 
     # if initial was provided, it should override the values from instance 
     if initial is not None: 
      object_data.update(initial) 
     # self._validate_unique will be set to True by BaseModelForm.clean(). 
     # It is False by default so overriding self.clean() and failing to call 
     # super will stop validate_unique from being called. 
     self._validate_unique = False 
     super(BaseModelForm, self).__init__(data, files, auto_id, prefix, object_data, 
              error_class, label_suffix, empty_permitted) 

    def _update_errors(self, message_dict): 
     for k, v in message_dict.items(): 
      if k != NON_FIELD_ERRORS: 
       self._errors.setdefault(k, self.error_class()).extend(v) 
       # Remove the data from the cleaned_data dict since it was invalid 
       if k in self.cleaned_data: 
        del self.cleaned_data[k] 
     if NON_FIELD_ERRORS in message_dict: 
      messages = message_dict[NON_FIELD_ERRORS] 
      self._errors.setdefault(NON_FIELD_ERRORS, self.error_class()).extend(messages) 

    def _get_validation_exclusions(self): 
     """ 
     For backwards-compatibility, several types of fields need to be 
     excluded from model validation. See the following tickets for 
     details: #12507, #12521, #12553 
     """ 
     exclude = [] 
     # Build up a list of fields that should be excluded from model field 
     # validation and unique checks. 
     for f in self.instance._meta.fields: 
      field = f.name 
      # Exclude fields that aren't on the form. The developer may be 
      # adding these values to the model after form validation. 
      if field not in self.fields: 
       exclude.append(f.name) 

      # Don't perform model validation on fields that were defined 
      # manually on the form and excluded via the ModelForm's Meta 
      # class. See #12901. 
      elif self._meta.fields and field not in self._meta.fields: 
       exclude.append(f.name) 
      elif self._meta.exclude and field in self._meta.exclude: 
       exclude.append(f.name) 

      # Exclude fields that failed form validation. There's no need for 
      # the model fields to validate them as well. 
      elif field in self._errors.keys(): 
       exclude.append(f.name) 

      # Exclude empty fields that are not required by the form, if the 
      # underlying model field is required. This keeps the model field 
      # from raising a required error. Note: don't exclude the field from 
      # validation if the model field allows blanks. If it does, the blank 
      # value may be included in a unique check, so cannot be excluded 
      # from validation. 
      else: 
       form_field = self.fields[field] 
       field_value = self.cleaned_data.get(field, None) 
       if not f.blank and not form_field.required and field_value in EMPTY_VALUES: 
        exclude.append(f.name) 
     return exclude 

    def clean(self): 
     self._validate_unique = True 
     return self.cleaned_data 

    def _post_clean(self): 
     opts = self._meta 
     # Update the model instance with self.cleaned_data. 
     self.instance = construct_instance(self, self.instance, opts.fields, opts.exclude) 

     exclude = self._get_validation_exclusions() 

     # Foreign Keys being used to represent inline relationships 
     # are excluded from basic field value validation. This is for two 
     # reasons: firstly, the value may not be supplied (#12507; the 
     # case of providing new values to the admin); secondly the 
     # object being referred to may not yet fully exist (#12749). 
     # However, these fields *must* be included in uniqueness checks, 
     # so this can't be part of _get_validation_exclusions(). 
     for f_name, field in self.fields.items(): 
      if isinstance(field, InlineForeignKeyField): 
       exclude.append(f_name) 

     # Clean the model instance's fields. 
     try: 
      self.instance.clean_fields(exclude=exclude) 
     except ValidationError, e: 
      self._update_errors(e.message_dict) 

     # Call the model instance's clean method. 
     try: 
      self.instance.clean() 
     except ValidationError, e: 
      self._update_errors({NON_FIELD_ERRORS: e.messages}) 

     # Validate uniqueness if needed. 
     if self._validate_unique: 
      self.validate_unique() 

    def validate_unique(self): 
     """ 
     Calls the instance's validate_unique() method and updates the form's 
     validation errors if any were raised. 
     """ 
     exclude = self._get_validation_exclusions() 
     try: 
      self.instance.validate_unique(exclude=exclude) 
     except ValidationError, e: 
      self._update_errors(e.message_dict) 

    def save(self, commit=True): 
     """ 
     Saves this ``form``'s cleaned_data into model instance 
     ``self.instance``. 

     If commit=True, then the changes to ``instance`` will be saved to the 
     database. Returns ``instance``. 
     """ 
     if self.instance.pk is None: 
      fail_message = 'created' 
     else: 
      fail_message = 'changed' 
     return save_instance(self, self.instance, self._meta.fields, 
          fail_message, commit, construct=False) 

    save.alters_data = True 

class ModelForm(BaseModelForm): 
    __metaclass__ = ModelFormMetaclass 

回答

2

你很可能需要給init的ModelForm在OrderCreateForm

class OrderCreateForm(ModelForm): 
    class Meta : 
     model=Order 
     fields=('work_type', 'comment',) 

    # *args and **kwargs will help you to main the compatibility with your parent 
    # class without to manage all arguments 
    def __init__(self, user_type, *args, **kwargs): 
     # ModelForm.__init__(self, *args, **kwargs) 
     # Usage of super is recommended. 
     super(OrderCreateForm, self).__init__(*args, **kwargs) 
     self.user_type = user_type 

     if self.user_type == 'foo': 
      queryset = User.objects.all() 
     else: 
      queryset = User.objects.filter(userprofle__user_type='bar') 

     self.creator = MyCustomField(
      queryset=queryset, 
      empty_label="Please select", 
      widget=forms.Select(attrs={'onchange':'some_ajax_function()'}) 
     ) 

是你需要什麼?

霍爾迪

+1

你應該使用'超(OrderCreateForm,個體經營).__的init __(* ARGS,** kwargs)',而不是明確指定超類。 – 2012-04-13 09:01:29

+0

等一下,爲什麼像'creator'和'queryset'這樣的其他所有東西都被定義在*'__init__'裏面? – hobbes3 2012-04-13 15:58:54

+0

'__init__'是類的初始化,你將會把實例需要運行的所有東西放進去。它就像一個總結。 實例變量('self.bar')不應該用'__init__'之外的另一種方法初始化。 – 2012-04-13 17:47:00