避免在django中对modelform字段进行新的实例化

时间:2016-07-06 23:51:00

标签: django django-forms

我有一个带有自定义modelchoicefield的模型表单。

class UserModelChoiceField(forms.ModelChoiceField):
    def label_from_instance(self, obj):
         return obj.get_full_name()

class TaskForm(forms.ModelForm):
    originator = UserModelChoiceField(queryset=User.objects.all().order_by('first_name'),widget=forms.Select(attrs={'class':'form-control'}))

    class Meta:
        model = Task
        fields = ['originator']

我的阅读建议以这种方式处理我的字段会覆盖模型中的任何信息(例如是否需要),因为它从我的定义中实例化它而不是增加模型的字段

似乎最小化我对这样的字段的更改我应该与init进行交互(见下文)

def __init__(self,*args, **kwargs):
    super(TaskForm, self).__init__(*args, **kwargs)

    self.fields['originator'].queryset=User.objects.all().order_by('first_name')
    self.fields['originator'].widget = forms.Select(attrs={'class':'form-control'})

我理解如何执行查询集和小部件,假设上述内容是正确的。我的问题是如何使用该自定义选择域。此外,我甚至不确定这是否是这样做的方式,因为它似乎有点hacky。

1 个答案:

答案 0 :(得分:1)

呃..我记得有这个问题而没有找到内置或惯用的解决方案。我没有提出比这个装饰更好的解决方案(是的,这是production code):

public class Example {
    private int a;

    public static final void main(String[] args) {
        new Example().go();;
    }

    Example() {
        this.a = 42;
    }

    void go() {
        System.out.println(a);      // 42, `a` is resolved to the instance field
        int a = 67;
        System.out.println(a);      // 67, `a` is resolved to the local because it
                                    // is "closer" to this code
        System.out.println(this.a); // 42, because we qualified it
    }
}

所以例如我会:

def model_generated(model):
    """Generate form fields from model fields

    Purpose:
        This decorator lets you have form field attributes like
        `max_length` copied over from a model field while being DRY.

    Usage:
        Decorate a form class with this decorator and set MODEL_GENERATED_FIELDS
        to a list of attribute names you would like to be generated.

    Limitations:
        - Currently, this decorator only supports CharFields.
    """

    def decorator(cls):

        for field_name in cls.MODEL_GENERATED_FIELDS:
            model_field = model._meta.get_field(field_name)

            model_field_type = type(model_field)
            if model_field_type == django_models.CharField:
                form_field_type = forms.CharField
                attributes = {  # (form_attribute, model_attribute, processor)
                    ('label', 'verbose_name', None),
                    ('max_length', None, None),
                    ('min_length', None, None),
                    ('required', 'blank', lambda value: not value),
                }
            else:
                # (Maybe one day this decorator will support more types of fields.)
                raise ValueError("Unknown type of model field: {}".format(model_field_type))

            kwargs = {}
            for form_attribute, model_attribute, processor in attributes:
                if model_attribute is None:
                    model_attribute = form_attribute
                if processor is None:
                    processor = lambda value: value

                if hasattr(model_field, model_attribute):
                    kwargs[form_attribute] = processor(getattr(model_field, model_attribute))

            form_field = form_field_type(**kwargs)
            setattr(cls, field_name, form_field)

            # Register field since we're monkey-patching
            # (Django's meta-class hackery to detect fields only runs the first time the class is declared.)
            cls.base_fields[field_name] = form_field

        return cls

    return decorator

 class Team(models.Model):
    name = models.CharField(max_length=30, unique=True,
                            verbose_name="Team Name")
    passphrase = models.CharField(max_length=30,
                                  verbose_name="Passphrase")
    ...

您可以根据自己的特定需求调整和扩展@model_generated(models.Team) class TeamJoiningForm(forms.Form): MODEL_GENERATED_FIELDS = ('name', 'passphrase') ... 装饰器。遗憾。