0

这可能更像是一个面向对象的 Python 问题。但它来自我问过的关于 Django的这个问题。

所以@burhan 建议不要在我的 Django 模板中手动写出我的自定义<select><option>标签,我应该只使用自定义ModelChoiceFieldforms.Select.

我当前继承ModelForm并创建了一个OrderCreateForm为我的模型调用的自定义表单Ordercreator'squeryset是基于creator'suser_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__我知道在类中创建参数__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
4

1 回答 1

4

您很可能需要在 OrderCreateForm 中初始化 ModelForm

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

那是你需要的吗?

霍尔迪

于 2012-04-13T02:06:18.690 回答