手动填充Django ModelForm的禁用字段

时间:2018-08-30 22:35:36

标签: django django-forms django-views

我面临以下情况:我有一个名为Contact的Django模型类,它看起来像:

class Contact(models.Model):
    first_name = models.CharField(max_length=70)
    last_name = models.CharField(max_length=70)

    company = models.ForeignKey(Company) // should be disabled in user-facing forms
    organizations = models.ManyToManyField(Organization) // should be disabled and hidden in user-facing forms

    // some other fields not relevant to this question

应用程序的用户和管理员都应该能够创建类型Contact的对象并将其存储在数据库中。但是,对于用户而言,应以无法自由选择Contact对象的公司字段的方式对此进行限制。为此,我创建了一个名为ModelForm的基础ContactForm(供管理员使用)和一个受限制的面向用户的子类RestrictedContactForm。代码如下:

class ContactForm(forms.modelForm):
    class Meta:
        model = Contact
        fields = ['first_name', 'last_name', 'company', 'organizations']

class RestrictedContactForm(ContactForm):
     class Meta(ContactForm.Meta):
         widgets = {'organizations': forms.HiddenInput()}

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

         // Maybe populate company and organization here somehow?

         self.fields['company'].disabled = True
         self.fields['organization'].disabled = True

RestrictedContactForm会在用户决定创建新联系人后呈现给用户。显然,由于companyorganization字段都是必填字段,因此需要以某种方式手动注入它们。我的问题恰恰在这里:我没有设法手动填充这些字段。

在下面,您可以找到实现用户发起的创建逻辑的视图功能的概述。

def create_contact(request, company_pk):
    company = Company.objects.get(pk=company_pk)
    organization = Organization.objects.get(...)

    if request.method == 'POST':
        // Add company.pk and organization.pk to POST here?

        // Pass data dictionary manually populated from POST and 
        // with company.pl and organization.pk to constructor?
        contact_form = RestrictedContactForm(request.POST, request.FILES)

        // Add company.pk and organization.pk to contact_form.data
        // here (after making it mutable)?

        if contact_form.is_valid():
            contact_form.save()
            return redirect(...)

        return render(...)

    contact_form = ContactForm(initial={'company': company, 'organizations': organization})

我已经尝试了上面评论中出现的所有建议。该表格根本无法验证。因此,我的问题是,这样做的正确方法是什么?此外,该方法至少在概念上是否正确?

该项目使用Django 1.9。

2 个答案:

答案 0 :(得分:0)

我一直使用form_valid方法完成此操作。在这种情况下,请使用子表单的form_valid方法:

def form_valid(self, form):
    form.instance.company = foo
    form.instance.organisation = bar
    return super().form_valid(form)

这将填充缺少的字段,然后保存表单。

答案 1 :(得分:0)

如果用户无法更改companyorganization字段,则不应将它们完全包含在RestrictedContactForm中的字段 中。

您可以做的是将organizationcompany的已知值传递到表单的构造函数中,然后将它们分配给对象,然后再在数据库中实际创建它。

>
class RestrictedContactForm(ContactForm):
     class Meta(ContactForm.Meta):
         fields = ['first_name', 'last_name', ]

     def __init__(self, company, organization, *args, **kwargs):
         super(RestrictedContactForm, self).__init__(*args, **kwargs)
         self.company = company
         self.organization = organization

     def save(self, commit=True):
        instance = super(RestrictedContactForm, self).save(commit=False)
        if not instance.pk:
            instance.company = self.company
            instance.organization = self.organization
        if commit:
            instance.save()
        return instance

def create_contact(request, company_pk):
        # ...
        if request.method == 'POST':
            company = Company.objects.get(pk=company_pk)
            organization = company.organization
            contact_form = RestrictedContactForm(company, organization, request.POST, request.FILES)
            # ...
        # ...