【问题标题】:POST request not working for Django form and Django formsetPOST 请求不适用于 Django 表单和 Django 表单集
【发布时间】:2020-05-30 09:20:51
【问题描述】:

我有一个表单 ApplyJobForm 和一个 Formset ApplyJobFormset。当我将表单和表单集传递给视图时,GET 方法有效,但是对于发布请求,表单和表单集 is_valid() 不起作用,单击提交后它会将我返回到视图而不保存。我无法使用表单集保存表单,我不知道我在这里做错了什么。 这是我的代码。

models.py

class Applicants(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    job = models.ForeignKey(Job, on_delete=models.CASCADE, related_name='applicants')
    experience = models.IntegerField(blank=True, null=True)
    cv = models.FileField(upload_to=user_directory_path)
    degree = models.CharField(choices=DEGREE_TYPE, blank=True, max_length=10)
    created_at = models.DateTimeField(default=timezone.now)

    def __str__(self):
        return f'{self.user.get_full_name()} Applied'


class Certification(models.Model):
    applicant = models.ForeignKey(Applicants, on_delete=models.CASCADE, related_name='applicant_certifications')
    name = models.CharField(max_length=50)
    certification = models.FileField(upload_to=user_directory_path, blank=True)

    def __str__(self):
        return f'{self.user.get_full_name()} certificate'

forms.py

class ApplyJobForm(forms.ModelForm):

    class Meta:
        model = Applicants
        fields = ('job', 'degree', 'experience', 'cv')
        exclude = ('job',)
        labels = {
            'degree': 'Degree',
            'experience': 'Experience',
            'cv': 'CV',
        }
        widgets = {
            'degree': forms.Select(attrs={
                'class': 'form-control',
            }
            ),
            'experience': forms.NumberInput(
                attrs={
                    'class': 'form-control',
                }
            ),
            'cv': forms.FileInput(
                attrs={
                    'class': 'form-control',
                }
            ),
        }


ApplyFormset = modelformset_factory(
    Certification,
    fields=('name', 'certification'),
    extra=1,
    widgets={
        'name': forms.TextInput(
            attrs={
                'class': 'form-control',
                'placeholder': 'Certification name'
            }
        ),
        'certification': forms.FileInput(
            attrs={
                'class': 'form-control',
                'placeholder': 'Upload certification'
            }
        )
    }
)

views.py

def job_apply(request, job_id=None):
    template_name = 'apply_form.html'
    applyform = ApplyJobForm(request.GET or None)
    job = get_object_or_404(Job, id=job_id)
    formset = ApplyFormset(queryset=Certification.objects.none())
    if request.method == 'GET':
        context = {'applyform': applyform, 'formset': formset}
        return render(request, template_name, context)
    elif request.method == 'POST':
        applyform = ApplyJobForm(request.POST)
        formset = ApplyFormset(request.POST)
        if applyform.is_valid() and formset.is_valid():
            apply = applyform.save(commit=False)
            applyform.job = job
            apply.save()
            for form in formset:
                # so that `apply` instance can be attached.
                certification = form.save(commit=False)
                certification.apply = apply
                certification.save()
            return redirect('successful-apply')
        else:
            return redirect('job-detail', id=job.id)

    return render(request, template_name, {'applyform': applyform, 'formset': formset})

在这里,申请人在申请工作时可以添加尽可能多的认证字段,尽管认证字段不是必填字段。认证模型与申请人模型绑定。

.html

<form class="form" method="POST" action="" enctype="multipart/form-data" role="form" autocomplete="off">
.................
</form>

【问题讨论】:

  • 在您的 job_apply 视图中,如果表单无效(else: 情况),您不应重定向,而只需再次使用表单呈现您的模板(并且希望在您的模板中显示表单错误)。所以完全删除else: return redirect(...),这样它就会转到return render(..) 行。

标签: django post django-forms formset


【解决方案1】:

首先,如果您的表单无效,从不重定向。您希望使用无效表单呈现您的模板,以便向用户显示错误。这也有助于调试,因为您会看到错误。

所以在你看来,删除这两行:

        else:
            return redirect('job-detail', id=job.id)

这样无效的情况就会呈现模板中的表单。

接下来,由于你有文件要上传,你需要用request.FILES初始化需要文件的表单:

formset = ApplyFormset(request.POST, request.FILES)

applyform 也是如此)。

最后确保在您的模板中还显示所有错误,无论是在每个字段 ({{ form.&lt;field&gt;.errors }}) 还是全局 ({{ form.errors }})。

【讨论】:

  • 好的,所以我删除了这两行,添加了 request.FILES 并再次尝试。现在我收到 NOT NULL constraint failed: nueoffshore_applicants.job_id 错误。
  • 因为您从未将 job 分配给表单实例 (apply)。你做了applyform.job = job,但这没用(表单没有属性job,所以你只是在这里定义它,无论如何你都在保存apply)。查看save(commit=False)documentation,其中有一个关于如何正确为实例分配值的示例。
  • 感谢我能够让它工作。我做了apply.job = job,然后是certification.applicant = apply。它能够提交
猜你喜欢
  • 2017-10-13
  • 2017-12-24
  • 2018-05-16
  • 2011-12-11
  • 1970-01-01
  • 2013-03-02
  • 1970-01-01
  • 2017-11-15
  • 2020-11-25
相关资源
最近更新 更多