Заполнение вручную отключенных полей Django ModelForm - PullRequest
0 голосов
/ 31 августа 2018

Я сталкиваюсь со следующим сценарием: у меня есть класс модели Django с именем Contact, который выглядит примерно так:

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 отображается пользователю, когда он решает создать новый контакт. Очевидно, что оба поля company и organization являются обязательными, их необходимо каким-то образом вводить вручную. Именно в этом и заключается моя проблема: Мне не удалось заполнить эти поля вручную.

Ниже вы можете найти схему функции представления, реализующей логику создания, инициированного пользователем.

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 голосов
/ 31 августа 2018

Если поля company и organization не могут быть изменены пользователем, то их не следует включать в список полей вообще в RestrictedContactForm.

Вместо этого вы можете передать известные значения для organization и company в конструктор формы, а затем назначить их объекту перед тем, как фактически создать его в базе данных.

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)
            # ...
        # ...
0 голосов
/ 31 августа 2018

Я всегда делал это, используя метод form_valid. В этом случае в методе form_valid дочерней формы:

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

Заполняет пропущенное поле, а затем сохраняет форму.

...