django - 使用一个表单创建两个模型实例

时间:2017-01-20 14:22:30

标签: python django django-forms

这似乎应该是相当简单的东西,应该是一个常见的东西需要,但我尝试找到的答案越多,我得到的就越混乱。

我有一个事件模型链接到需要事件的多个其他模型,所以我为它创建了一个单独的事件模型。现在,我想在创建工作模型时创建一个事件,但我无法弄清楚如何去做。

在我的工作领域,我与一个事件有一个OneToOneField关系,而我在做事件时唯一需要决定的就是持续时间。

简化的工作模型可能如下所示:

class Job(models.Model):
    customer = models.ForeignKey(Customer)
    address = models.CharField(max_length=100, verbose_name="Job Address", null=False, blank=False)
    city = models.CharField(max_length=100, verbose_name="City", null=True, blank=True)
    state = models.CharField(max_length=2, verbose_name="State", null=True, blank=True)
    zip = models.CharField(max_length=5, verbose_name="Zip Code", null=True, blank=True)
    # Simply need to set duration
    event = models.OneToOneField(Event, on_delete=models.CASCADE, null=False, blank=False)

简化的事件模型可能如下所示:

class Event(models.Model):

    TIME_LIST = (
        (1, "0:30"),
        (2, "1:00"),
        (3, "1:30"),
        (4, "2:00"),
        (5, "2:30"),
        (6, "3:00"),
        (7, "3:30"),
        (8, "4:00"),
        (9, "4:30"),
        (10, "5:00"),
        (11, "5:30"),
        (12, "6:00"),
        (13, "6:30"),
        (14, "7:00"),
        (15, "7:30"),
        (16, "8:00"),
    )

    title = models.CharField(max_length=255)
    employee = models.ForeignKey(Employee, null=True, blank=True)
    start_time = models.DateTimeField(null=True, blank=True)
    end_time = models.DateTimeField(null=True, blank=True)
    range = RecurrenceField(null=True, blank=True)
    duration = models.IntegerField(choices=TIME_LIST, null=True, blank=True)
    is_all_day = models.BooleanField(default=False, null=False, blank=False)

我正在使用通用CBV,所以简单地说:

class JobCreate(CreateView):
    template_name = 'jobs/create.html'
    success_url = '/schedule/add/'
    form_class = JobCreateForm

    def get_success_url(self):
        return self.success_url + str(self.object.id)

我的表格可以简单地说:

class JobCreateForm(forms.ModelForm):
    class Meta:
        model = Job
        fields = [
            'customer',
            'address',
            'city',
            'state',
            'zip',
        ]

我需要的是一种方法,我可以在我的工作表单中创建一个选择框,然后创建一个新的Event实例,将ev​​ent_id插入我的工作模型的事件字段,并将其全部提交到一个去。

我看了inlineformset_factory,这似乎应该是我需要的东西,而且我一直在犯错,所以这是错误的想法,或者我使用它错了。我尝试了其他人建议的一些mixins,它们看起来有点矫枉过正,无论如何都不适合我。

2 个答案:

答案 0 :(得分:2)

您可以为Event创建第二个表单,并在模板中呈现它。然后在您的视图中,您可以先保存它,创建一个事件,然后保存您的Job表单并将其相关事件设置为刚创建的事件。

或者(我可能会这样做),如果您更喜欢单一表单,则可以在工作表单中添加持续时间字段并覆盖表单{{1}功能。重写的保存可能看起来像这样

save

Formsets实际上是用于制作多个表单,所以在您使用def save(self, commit=True): e = Event.objects.create(duration=self.cleaned_data.get('duration')) job = super().save(commit=False) job.event = e job.save() return job 的情况下(因此只创建需要单个表单来创建单个相关对象),使用它是没有意义的它们。

答案 1 :(得分:0)

我刚刚意识到我接受的答案并不完全正确。出于某种原因(django magic),save被多次调用,一次用于获取数据,一次用于保存,因此每次创建作业时都会生成两个事件实例。另一个问题是,在保存作业之前还必须保存事件,或者尝试运行job.save()会抛出错误。我通过使用以下代码解决了这个问题。

def save(self, commit=True):
    job = super(JobCreateForm, self).save(commit=False)
    if commit:
        event = Event(duration=self.cleaned_data.get('duration'), title=self.cleaned_data.get('customer'))
        event.save()
        job.event = event
        job.save()
    return job