Django создает действительную ModelForm с неполной моделью, чтобы вручную добавлять поля после проверки формы.

Как вы создаете почтовый запрос, чтобы ModelForm был действительным (предоставляя вам все, что нужно заполнить пользователю), но затем изменяете модель (со всем, что пользователь не должен предоставлять вам [например, имя пользователя/профиль, дату и время, другие вычисляемые переменные и т.д...]) перед проверкой формы/набора форм в представлении?

Образец кода:

просмотры.py

def view(request):
    # Create the formset, specifying the form and formset we want to use.
    LowerFormSet = formset_factory(LowerForm, formset=BaseLowerFormSet, extra=0)

    # If they are posting data
    if request.method == 'POST':
        # Grab the data they submitted
        formData = request.POST
        # highestForm = MealForm(formData, meal=meal, prefix='recipe')

        lower_formset = LowerFormSet(formData, prefix='lower_formset')

        lower_form in lower_formset:
            lower_form.instance.a = A.objects.create(…)

            # HERE
            # Each form isn't valid, because it is missing its associated higher object, despite not including the field in the ModelForm
            lower_form.save()
            # But if we create a foreign key/higher object and add it here, we are circumventing the  validation step, and creating objects when the validation might not be True
            lower_form.instance.higher = Higher.objects.create(…)
            lower_form.save()
            # How do you separate these concerns, so you can create a valid Model Form, then add the necessary parts after the validation?

        # Check for valid data
        if all([otherForm.is_valid(),
                lower_formset.is_valid(),
                other_formset.is_valid(),
                ]):
            # make the Higher here, and add it to each form
            for form in lower_formset:
                form.higher = higher
                form.save()

            return HttpResponseRedirect(reverse('recipe:success'))
        else:
            return response = render(request, 'template', {…})
    else:
        # …

модели.py

class Lower(models.Model):
    higher = models.ForeignKey(Higher, related_name="higher")
    # Etiher A or B is required, depending on information from the foreign key of the Higher
    a = models.ForeignKey(A, blank=True, null=True, related_name="switch_case")
    b = models.ForeignKey(B, blank=True, null=True, related_name="switch_case")
    createdAt = models.DateTimeField(auto_now_add=True)

    def clean(self):
        if self.higher.a:
            if not self.a:
                raise AssertionError("The higher wants a, but you did not provide a")
            if self.b:
                raise AssertionError("The higher wants a, but you provided b")
        else:
            if not self.a:
                raise AssertionError("The higher wants b, but you provided a")
            if self.b:
                raise AssertionError("The higher wants b, but you did not provide b")

    def save(self, *args, **kwargs):
        self.clean()
        super(Lower, self).save(*args, **kwargs)

person chris Frisina    schedule 19.08.2018    source источник


Ответы (1)


Вы немного сбиваете себя с толку, думая о недопустимых формах. Форма всегда должна быть допустимой, прежде чем вы что-либо с ней сделаете, но это не значит, что она должна представлять действительный экземпляр модели. Что вам нужно сделать, так это исключить поля, которые вы не хотите показывать пользователю, а затем установить их в экземпляре впоследствии.

class LowerForm(forms.ModelForm):
    class Meta:
        model = Lower
        exclude = ['higher']

и вид:

lower_formset = LowerFormSet(formData, prefix='lower_formset')

if lower_formset.is_valid():   # perform validation
    for lower_form in lower_formset:
        lower = lower_form.save(commit=False)  # create a Lower instance but don't save to db yet
        lower.higher = Higher.objects.create(…)
        lower.save()
person Daniel Roseman    schedule 19.08.2018
comment
каким-то образом метод очистки модели вызывается во время full_clean набора форм, и это кажется усложнением, несмотря на включение excludes - person chris Frisina; 20.08.2018
comment
я думаю, что ваша логика не в том месте. Почему он в модели вообще чистый? Но что более важно, как вы определяете в представлении, какое ВЫСШЕЕ вам нужно? Разве вы не можете использовать ту же логику в форме, чтобы определить, нужен ли вам A или B? - person Daniel Roseman; 20.08.2018
comment
Я поместил его в модель, чтобы убедиться, что он правильный (не оба). Я проверяю, какой тип (A или B) для POST нижнего представления (поддерживается шаблоном, предоставляющим соответствующую форму AForm или BForm). Если я создаю объект более высокого уровня перед проверкой, чтобы передать объект более низкого уровня, чтобы сделать объект более низкого уровня действительным, я обхожу проверку. Если я жду проверки, кажется, что набор форм вызывает _post_clean(), который, в свою очередь, вызывает full_clean(), который вызывает clean(). Если два (ModelForm и Model) должны быть такими же отдельными, как вы предложили (и я закодировал ранее), то почему чистые вызовы? - person chris Frisina; 20.08.2018
comment
Я поместил его в модель, а также подумал, что проверку на уровне БД следует учитывать, когда она полностью абстрагируется до атомарного уровня, насколько это возможно (я уже использую модифицированную структуру GFK с таблицами, связанными с типами отношений). - person chris Frisina; 20.08.2018