Django 2.0:如何在 1 个视图中保存 3 个 ModelForms

Django 2.0: How to save 3 ModelForms in 1 view

如何从一个视图中保存来自 3 个 FormModel 的输入?

您好 Whosebug,这是我第一次 post 来到这里。我刚开始在 Python/Django 中学习编码,所以我的代码可能根本不正确,对此深表歉意。

经过三天的搜索和大量代码的尝试,我希望有知识的人:)

我想做什么:

一张大表:用户填写个人字段、档案字段和第二人的信息。 (部分内容目前未正确保存)

Views.py 2 个 ModelForms 的一个视图,并再次为 c_person 重用一个视图。 Models.py 2 个模型(一个档案和一个人的数据模型)。 Forms.py 2 个模型表单(一个来自档案,一个来自个人,在视图中重复使用个人表单)。

dossier.html 数据给出了表格的概念(删除了很​​多代码)。

                                    <div class="column is-one-fifth">
                                    <label class="label is-small">Firstname</label>
                                    {{ person_form.first_name }}
                                </div>

                                <div class="column is-one-fifth">
                                    <label class="label is-small">Preposition</label>
                                    {{ person_form.preposition }}
                                </div>

                                <div class="column is-one-fifth">
                                    <label class="label is-small">Lastname</label>
                                    {{ person_form.last_name }}
                                </div>

                                <div class="column is-one-fifth">
                                    <label class="label is-small">Address</label>
                                    {{ person_form.address }}
                                </div>

                                <div class="column is-one-fifth">
                                    <label class="label is-small">Firstname</label>
                                    {{ cperson_form.first_name }}
                                </div>

                                <div class="column is-one-fifth">
                                    <label class="label is-small">Lastname</label>
                                    {{ cperson_form.last_name }}
                                </div>

                                <div class="column is-one-fifth">
                                    <label class="label is-small">Number</label>
                                    {{ cperson_form.number }}
                                </div>

                                <div class="column is-one-fifth">
                                    <label class="label is-small">Status</label>
                                    {{ dossier_form.status }}
                                </div>

                                <div class="column is-one-fifth">
                                    <label class="label is-small">Operator</label>
                                    <div class=select>{{ dossier_form.operator }}</div>
                                </div>

models.py

class Person(models.Model):

number = models.IntegerField(unique=True, null=True, blank=True)
first_name = models.CharField(max_length=35, null=True, blank=True)
last_name = models.CharField(max_length=35, null=True, blank=True)
initials = models.CharField(max_length=10, null=True, blank=True)
preposition = models.CharField(max_length=10, null=True, blank=True)
address = models.CharField(max_length=80, null=True, blank=True)
address_number = models.CharField(max_length=5, null=True, blank=True)
email = models.EmailField(null=True, blank=True)
phone_number = models.IntegerField(null=True, blank=True)

@property
def full_name(self):
    "Returns the person's full name"
    full_name = (self.last_name + ', ' + self.first_name)

    # Need to check this, django return 'None' if no preposition is used
    if self.preposition:
        full_name = full_name + ' ' + self.preposition

    return full_name

def __str__(self):
    return self.first_name + ' ' + self.last_name

class Dossier(models.Model):
# Core
status = models.ForeignKey('DossierStatus', null=True, on_delete=models.SET_NULL)
operator = models.ForeignKey('User', null=True, on_delete=models.SET_NULL)
d_person = models.ForeignKey('Person', related_name='d_person', null=True, on_delete=models.SET_NULL, blank=True)
c_person = models.ForeignKey(Person, related_name='c_person', null=True, on_delete=models.SET_NULL, blank=True)


def __int__(self):
    return self.id

def get_absolute_url(self):
    return reverse('dossier_edit', kwargs={'pk': self.pk})

forms.py

class PersForm(forms.ModelForm):
class Meta:
    model = Person
    fields = ['number', 'first_name', 'preposition', 'last_name', 'initials', 'address', 'address_number', 'email', 'phone_number']

class DossierForm(forms.ModelForm):
class Meta:
    model = Dossier
    fields = '__all__'

views.py

def dossier(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
    # create a form instance and populate it with data from the request:
    dossier_form = DossierForm(request.POST, request.FILES)
    dossier_form_valid = dossier_form.is_valid()
    person_form = PersForm(request.POST)
    person_form_valid = person_form.is_valid()
    cperson_form = PersForm(request.POST)
    cperson_form_valid = cperson_form.is_valid()
    # check whether it's valid:
    if dossier_form_valid and person_form_valid and cperson_form_valid:
        print("succes")
        # process the data 
        person_save = person_form.save()
        dossier_save = dossier_form.save(commit=False)
        cperson_save = cperson_form.save(commit=False)

        dossier_save.person_save = person_save
        cperson_save.dossier_save = dossier_save
        cperson_save.save()

        # redirect to a new URL:
        return HttpResponseRedirect('/data/index/')
    else:
            print("failure")
            print(dossier_form.errors)
            print(person_form.errors)

# if a GET (or any other method) we'll create a blank form
else:
    dossier_form = DossierForm()
    person_form = PersForm()
    cperson_form = PersForm()

return render(request, 'dossier.html',
              {'title': 'Nieuwe aanvraag', 'dossier_form': dossier_form,
               'person_form': person_form, 'cperson_form': cperson_form})

这里的问题是只有一个人的表单数据被保存到数据库中。 我在这段代码上尝试了很多不同的变体:

        person_save = person_form.save()
        dossier_save = dossier_form.save(commit=False)
        cperson_save = cperson_form.save(commit=False)

        dossier_save.person_save = person_save
        cperson_save.dossier_save = dossier_save
        cperson_save.save()

在模型表单中将 commit 参数传递给 save() 方法时,它会将您的模型保存在数据库中。我看到这里的 commit 术语有点误导,因为它听起来像 提交数据库事务 ,但它纯粹是定义模型的 save() 方法是否将是叫不叫。

您要做的是使用 django.models.db.transaction.

将所有这些代码包装在一个数据库事务中

首先将其导入您的视图:

from django.db.models import transaction

那么你可以这样使用它:

if dossier_form_valid and person_form_valid and cperson_form_valid:
    print("succes")
    # process the data 

    with transaction.atomic():
        d_person = person_form.save()
        c_person = cperson_form.save()

        dossier = dossier_form.save(commit=False)
        dossier.d_person = d_person
        dossier.c_person = c_person
        dossier.save()

模型形式 save() 方法 returns 它代表的 Django 模型实例。所以它将它重命名为 dossier 而不是 dossier_save,等等

dossier_form 中你可以使用 commit=False 因为你有更多的数据与 dossier 相关联,这样你就可以避免多次调用 save() 方法.但是为了让对象持久保存在数据库中,在添加额外数据后,您需要调用 dossier.save().

之类的保存方法

transaction.atomic() 块内的所有内容都将在单个数据库事务中执行,如果发生错误,Django 将自动回滚。

Vitor 的响应是正确的,但是,导入已更改为:

from django.db.models import transaction

已更改为:

from django.db import transaction