2012-04-13 5 views
0

Dies könnte eher eine OO Python Frage sein. Aber es kam von this question Ich fragte nach Django.Wie übergibt man eine Variable an eine geerbte Klasse in Python/Django?

So geraten @burhan dass statt meiner benutzerdefinierten <select> und <option> Tag in meinem Django-Vorlage manuell auszuschreiben, sollte ich nur eine benutzerdefinierte ModelChoiceField und forms.Select verwenden.

ich aktuelle inherit ModelForm und erstellen Sie eine benutzerdefinierte Form genannt OrderCreateForm für mein Modell Order, die creator ‚s queryset basiert auf, was die creator‘ s user_type ist und somit muss ich irgendwie eine Variable zur Gewohnheit passieren ModelForm zu sein in der Gewohnheit verwendet ModelChoiceField.

So schließlich mag ich so etwas wie diese

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

Ich weiß, dass Parameter in einer Klasse etwas mit __init__ zu tun hat, zu schaffen, aber ich bin ein OO-Neuling und ich war nicht sicher, ob meine eigene Schaffung __init__ steht in Konflikt mit ModelForm.__init__. Auch möchte ich meine benutzerdefinierte ModelForm Klasse wie form=OrderCreateForm(user_type='foo_bar') anrufen. Würde das möglich sein.

Sorry, wenn meine Frage verwirrend ist, wie ich schon sagte, ich bin ein OO-Neuling und ich kenne nicht die ganze Terminologie und das Konzept so gut.

EDIT: Hier einige Quellcode von Django in Bezug auf 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 

Antwort

2

Sie werden höchstwahrscheinlich die Modelform in Ihrem 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()'}) 
     ) 

Ist init müssen das, was Sie brauchen?

Jordi

+1

Sie sollten 'Super (OrderCreateForm, Selbst-) verwenden .__ init __ (* args, ** kwargs)' stattdessen die übergeordnete Klasse explizit zu benennen. –

+0

Warte, warum sollte alles andere wie 'creator' und' queryset' definiert sein * innerhalb * '__init__'? – hobbes3

+0

'__init__' ist die Initialisierung der Klasse und Sie fügen alles ein, was die Instanz ausführen soll. Es ist wie eine Zusammenfassung. Eine Instanzvariable ('self.bar') sollte nicht in einer anderen Methode als'__init__' initialisiert werden –