Django是否可以在初始提交模型表单时使用内联表格集?

时间:2013-05-09 05:42:23

标签: python django

我看过很多类似的帖子,但没有足够的信息来帮助我。

免责声明:我是非常 Django的新手。

我正在尝试为我的公司创建一个将在子域(例如jobs.mycompany.com)上托管的就业申请 - 这是我的第一个真正的Django项目。我希望为最终用户完成的工作已在管理部分完成。

基本上,我将工作申请分解为几个部分:

  • 申请人(只能有其中一个
  • 教育(教育记录[即学校] - 可以是多个
  • Job_Experience(组织申请人在 - 可以是多个
  • 可用性(与Highlander一样,只能有一个

这是问题 - 我不认为我正确地将它放入一个表格中,而且我也不知道如何一次保存所有这些。我尝试EducationJob_Experience制作表单集,但我认为我也没有正确应用这些表单。

基本上,我希望所有这些都出现,当用户点击“提交”时,它会创建所有必要的记录 - 申请人和可用性是实际需要的唯一部分。

修改

要重新迭代:管理面板正在完成我想要在前端实现的目标。,但是(在前端)我无法做到:

  • applicant选择器输入消失
  • applicant个实例分配给非申请人型号
  • 我可能错了,但我认为可能有一种方法可以将这些表单统一到一个实例中,而不是按照我现在的方式将多个实例传递给视图。

以下代码:

models.py

from django.db import models
from django import forms
from django.forms import ModelForm
from datetime import datetime

class Applicant(models.Model):
    name = models.CharField(max_length=200)
    city = models.CharField(max_length=200)
    state = models.CharField(max_length=200)
    zip = models.CharField(max_length=200)
    social_security_number = models.CharField(max_length=200)
    phone = models.CharField(max_length=200)
    alt_phone = models.CharField(max_length=200, blank=True)
    us_citizen = models.BooleanField()
    committed_felony = models.BooleanField()
    is_16 = models.BooleanField()
    has_drivers_license = models.BooleanField()
    is_disabled = models.BooleanField()
    prev_employed = models.BooleanField()
    felony_explanation = models.TextField(blank=True)
    disabled_explanation = models.TextField(blank=True)
    prev_employment_manager = models.CharField(max_length=200, blank=True)
    prev_employment_year = models.CharField(max_length=4, blank=True)
    skills = models.TextField()

    def __unicode__(self):
        return self.name

class Education(models.Model):
    GED = 'GED'
    HIGH_SCHOOL = 'HIG'
    JUNIOR_COLLEGE = 'JUN'
    UNIVERSITY = 'UNI'
    TYPE_OF_SCHOOL_CHOICES = (
        (GED, 'GED'),
        (HIGH_SCHOOL, 'High School'),
        (JUNIOR_COLLEGE, 'Junior College'),
        (UNIVERSITY, 'University'),
    )

    type = models.CharField(
        max_length=3,
        choices=TYPE_OF_SCHOOL_CHOICES,
        default=HIGH_SCHOOL
    )
    school_name = models.CharField(max_length=200)
    school_city = models.CharField(max_length=200)
    school_state = models.CharField(max_length=200)
    graduated = models.BooleanField()
    graduation_year = models.CharField(max_length=4)
    applicant = models.ForeignKey(Applicant)

class Job_Experience(models.Model):
    FULL_TIME = 'F'
    PART_TIME = 'P'
    FTPT_CHOICES = (
        (FULL_TIME, 'Full Time'),
        (PART_TIME, 'Part Time'),
    )

    organization_name = models.CharField(max_length=200)
    organization_city = models.CharField(max_length=200)
    organization_state = models.CharField(max_length=200)
    supervisor_name = models.CharField(max_length=200)
    supervisor_phone = models.CharField(max_length=200)
    supervisor_contact_allowed = models.BooleanField()
    currently_employed = models.BooleanField()
    start_date = models.DateField()
    end_date = models.DateField()
    starting_title = models.CharField(max_length=200)
    ending_title = models.CharField(max_length=200)
    start_salary = models.CharField(max_length=20)
    end_salary = models.CharField(max_length=20)
    reason_for_leaving = models.TextField()
    full_time_part_time = models.CharField(
        max_length = 1,
        choices = FTPT_CHOICES,
        default = PART_TIME
    )
    applicant = models.ForeignKey(Applicant)

class Availability (models.Model):
    NOT_AVAILABLE = 'XX'
    OPEN_AVAILABILITY = 'OP'
    AVAILABLE_BETWEEN = 'AB'
    AVAILABILITY_CHOICES = (
        (NOT_AVAILABLE, 'Not Available'),
        (OPEN_AVAILABILITY, 'Available All Day'),
        (AVAILABLE_BETWEEN, 'Available Between Certain Hours'),
    )

    mon_availability = models.CharField(
        max_length = 2,
        choices = AVAILABILITY_CHOICES,
        default = NOT_AVAILABLE
    )
    mon_hours_start = models.CharField(max_length = 10)
    mon_hours_end = models.CharField(max_length = 10)
    tue_availability = models.CharField(
        max_length = 2,
        choices = AVAILABILITY_CHOICES,
        default = NOT_AVAILABLE
    )
    tue_hours_start = models.CharField(max_length = 10)
    tue_hours_end = models.CharField(max_length = 10)
    wed_availability = models.CharField(
        max_length = 2,
        choices = AVAILABILITY_CHOICES,
        default = NOT_AVAILABLE
    )
    wed_hours_start = models.CharField(max_length = 10)
    wed_hours_end = models.CharField(max_length = 10)
    thu_availability = models.CharField(
        max_length = 2,
        choices = AVAILABILITY_CHOICES,
        default = NOT_AVAILABLE
    )
    thu_hours_start = models.CharField(max_length = 10)
    thu_hours_end = models.CharField(max_length = 10)
    fri_availability = models.CharField(
        max_length = 2,
        choices = AVAILABILITY_CHOICES,
        default = NOT_AVAILABLE
    )
    fri_hours_start = models.CharField(max_length = 10)
    fri_hours_end = models.CharField(max_length = 10)
    fri_availability = models.CharField(
        max_length = 2,
        choices = AVAILABILITY_CHOICES,
        default = NOT_AVAILABLE
    )
    sat_hours_start = models.CharField(max_length = 10)
    sat_hours_end = models.CharField(max_length = 10)
    sat_availability = models.CharField(
        max_length = 2,
        choices = AVAILABILITY_CHOICES,
        default = NOT_AVAILABLE
    )
    sun_hours_start = models.CharField(max_length = 10)
    sun_hours_end = models.CharField(max_length = 10)
    applicant = models.OneToOneField(Applicant)

# Forms

class ApplicantForm(ModelForm):
    class Meta:
        model = Applicant

class EducationForm(ModelForm):
    class Meta:
        model = Education

class JobExperienceForm(ModelForm):
    class Meta:
        model = Job_Experience

class AvailabilityForm(ModelForm):
    class Meta:
        model = Availability

views.py

from django.shortcuts import render
from django.http import HttpResponse
from django.template import Context, loader
from applications.models import Applicant, Education, Job_Experience, Availability, ApplicantForm, EducationForm, JobExperienceForm, AvailabilityForm
from django.forms.formsets import formset_factory


def index(request):
    education_formset = formset_factory(EducationForm, extra=3)
    message = 'Forms have not been submitted.'

    if request.method == 'POST':
        applicant_form = ApplicantForm(request.POST)
        education_form = education_formset(request.POST)
        if applicant_form.is_valid() and education_form.is_valid():
            applicant_form.save()
            education_form.applicant = applicant_form
            message = 'Forms are valid.'
        else:
            message = 'Forms are not valid.'
    else:
        applicant_form = ApplicantForm()
        education_form = education_formset()

    return render(request, 
        'applications/index.html', 
        {
            'applicant_form' : applicant_form,
            'education_form' : education_form,
            'message' : message
        }
    )

admin.py

from django.contrib import admin
from applications.models import Applicant, Education, Job_Experience, Availability

class EducationInline(admin.StackedInline):
    model = Education
    extra = 3

class JobExperienceInline(admin.StackedInline):
    model = Job_Experience
    extra = 3

class AvailabilityInline(admin.StackedInline):
    model = Availability

class ApplicantAdmin(admin.ModelAdmin):
    inlines = [EducationInline, JobExperienceInline, AvailabilityInline]

admin.site.register(Applicant, ApplicantAdmin)

的index.html

<h1>Employment Application</h1>
<p>Please enter your information into the fields below.</p>
<hr />
<p>{{ message }}</p>
<hr />
<form action="{% url 'applications:index' %}" method="post">
    {% csrf_token %}
    {{ applicant_form.as_p }}
    <hr />
    {{ education_form.as_p }}
    <input type="submit" />
</form>

2 个答案:

答案 0 :(得分:1)

我意识到这已经有几个月了,也许你已经使用Django解决了这个问题,或者现在正在使用别的东西,但你非常接近。您的用例的基本视图模式是:

  1. 设置formset
  2. 验证父表单
  3. 验证formset
  4. 如下所示:

    def index(request):
    
        EducationFormSet = formset_factory(
            Application,
            Education,
            form=EducationForm,
            extra=3,
        )
    
        if request.method == 'POST':
            application_form = ApplicationForm(request.POST)
    
            if application_form.is_valid():
                application = application_form.save(commit=False)
                education_formset = EducationFormSet(request.POST, instance=application)
    
                if education_formset.is_valid():
                    application.save()
                    education_formset.save()
    
                    return HttpResponseRedirect(reverse('thanks_and_good_luck_view'))
            else:
                education_formset = EducationFormSet(request.POST)
        else:
            application_form = ApplicationForm()
            education_formset = EducationFormSet()
    
        return render_to_response(
            'applications/index.html',
            {
                'application_form': application_form,
                'education_formset': education_formset,
            },
            context_instance=RequestContext(request)
        )
    

    保存父表单时,这里的棘手问题是commit=False。这允许您获取父模型的未提交实例以用于formset中的子模型实例。

答案 1 :(得分:0)

据我了解您的问题,您需要在前端使用相同的管理员内联功能。

django管理应用程序使用自定义jquery作为其前端。部分原因是自动生成子表单。

要在您自己的前端开始使用它,请从文档中的formsets部分开始。这将为您提供有关多个子表单在视图中如何工作的基本概念。然后,您可以转到inline formsets,这是管理员用来呈现其表单的内容。

对于javascript部分,您可以使用django-dynamic-formset或更全面的内容,例如crispy forms,以便为dynamic inlines提供更好的呈现和支持。