【问题标题】:how to add a different model form to modelformset_factory如何将不同的模型表单添加到 modelformset_factory
【发布时间】:2020-06-07 14:23:48
【问题描述】:

关于这些模型:

class Projects(models.Model):
    projectDescription = models.CharField(max_length=50,blank=True,null = True,)
    status = models.IntegerField(choices = Status_CHOICES, default = 4)
    projectOwner = models.ForeignKey(staff, on_delete=models.CASCADE, blank=True,null = True,)

class Updates(models.Model):
    project = models.ForeignKey(Projects, on_delete=models.CASCADE)
    update = models.CharField(max_length=50,blank=True,null = True,)
    updateDate = models.DateTimeField(default = timezone.now, editable = False)
    addedBy = models.CharField(max_length=35,blank=True,)

我想创建一个显示所有当前项目的表单的视图。这很容易使用modelformset_factory。但是我怎样才能为每个项目表单实例添加一个额外的表单,以便可以对项目(外键)进行 更新? 理想情况下,用户对各种项目进行更改,为一个或多个项目添加更新,然后提交表单以保存所有更改。 我在下面的内容似乎非常接近,但它正在保存每个项目的更新,其中包含我在最后一个表单中输入的任何值。这似乎是因为形式不是唯一的。我走上了使用前缀的道路,这似乎也没有让我到任何地方。帮忙!

更新表格

class updateForm(ModelForm):
    def __init__(self, *args, **kwargs):
        super(updateForm, self).__init__(*args, **kwargs)
    class Meta:
        model = Updates
        fields = ('update',)

查看:

def MDSprojects(request):
    projects = Projects.objects.filter(dept = 'Assistive Technology')
    projectFormset = modelformset_factory(Projects, form=EditProjectForm, extra = 0)

    if request.method == 'POST':
        formsetA = projectFormset(request.POST,request.FILES)
        if formsetA.is_valid():
            for f in formsetA:
                formA = f.save(commit = False)
                id = formA.id
                formA.save()
                formsetB = updateForm(request.POST,request.FILES)
                if formsetB.is_valid():
                    formB = formsetB.save(commit = False)
                    project = Projects.objects.get(id = id)
                    formB.project = project
                    formB.save()
                else:
                    print(formsetB.errors)
            return redirect('MDS_Projects')
        else:
            print(formsetA.errors)
    else:
        formsetA = projectFormset(queryset = projects)
        formsetB = updateForm()
        return render(request,'MDSprojectsB.html',{'formset':formsetA,'formsetB':formsetB,})

模板:

<form method="POST" enctype= multipart/form-data>
  {{ formset.management_form }}
  {% csrf_token %}
  {%for form in formset%}
    {{ form.management_form }}
    {% for hidden in form.hidden_fields %}
      {{ hidden }}
    {% endfor %}
  <div class="card border-primary mb-3" style="max-width: 85rem;">
    <div class="card-header text-primary">
       <strong>{{form.instance.projectDescription}}</strong>
    </div>
    <div class="card-body text-primary"> Project Name: {{form.projectDescription}}</div>
    <div class="card-body text-primary"> Status: {{form.status}}</div>
    <div class="card-body text-primary"> Status: {{form.projectOwner}}</div>
    <div class="card-body text-primary"> Status: {{form.priority}}</div>
    <div>
        {{ formsetB.management_form }}
        {% for hidden in formsetB.hidden_fields %}
          {{ hidden }}
        {% endfor %}
        {{formsetB}}
    </div>
  </div>
  {% endfor %}
  <button class="btn btn-success btn" type="submit">Save Changes</button>
 </form>

编辑:

也许另一种解释我的问题的方式是:

如果我有与上面相同的模型:

class Projects(models.Model):
    projectDescription = models.CharField(max_length=50,blank=True,null = True,)
    status = models.IntegerField(choices = Status_CHOICES, default = 4)
    projectOwner = models.ForeignKey(staff, on_delete=models.CASCADE, blank=True,null = True,)

class Updates(models.Model):
    project = models.ForeignKey(Projects, on_delete=models.CASCADE)
    update = models.CharField(max_length=50,blank=True,null = True,)
    updateDate = models.DateTimeField(default = timezone.now, editable = False)
    addedBy = models.CharField(max_length=35,blank=True,)

我想要一个视图,将所有当前项目呈现为单独的表单,以便用户可以在一个视图中更改项目模型。此外,我希望用户也能够为每个项目添加更新。

例如,如果我有 3 个项目,我希望在页面上看到 3 个表单。每个表单都将包含修改此项目的字段(因此这些表单字段将预先填充当前值)。最后(我坚持的部分)将是一个额外的空白字段,用于向项目添加更新。

【问题讨论】:

  • 如果你有2个项目,projectA; projectB 和这些项目有更新 A1、A2、A3、B1、B2。您要显示项目 A 的表格,然后显示 A1、A2、A3 的更新表格和项目 B 的表格,然后显示 B1、B2 的更新表格。我没有得到你想要的结果。
  • 嗨@ismail Taha AYKAC,我在我的问题中添加了一些额外的说明。我想查看每个项目的表单,并且在同一个表单上,我想要一个空输入字段来为项目添加更新。所以项目表单是要编辑的,而更新表单字段是要添加的。希望这是有道理的。

标签: python django django-forms django-views


【解决方案1】:

解决方案一

你所做的几乎是正确的。您已经启动了一个 UpdateForm,但您将它视为一个表单集。但是它是一个 Form 实例。如果您按以下方式更改代码,您可能会实现您的目标。

模型.py

class Project(models.Model):
    description = models.CharField(max_length=50, blank=True, null=True)
    status = models.IntegerField(choices=STATUS_CHOICES, default=4)
    owner = models.ForeignKey(staff, on_delete=models.CASCADE, blank=True, null=True)
    ...

class Update(models.Model):
    project = models.ForeignKey(Project, on_delete=models.CASCADE)
    notes = models.CharField(max_length=50, blank=True, null=True)
    update_date = models.DateTimeField(default=timezone.now, editable=False)
    added_by = models.CharField(max_length=35, blank=True)

forms.py

class CreateUpdateForm(ModelForm):
    class Meta:
        model = Update
        fields = ('notes')


class EditProjectForm(ModelForm)
    class Meta:
        model = Project
        fields = ('__all__')

views.py

def mds_projects(request):
    project_formset = modelformset_factory(Project, form=EditProjectForm, extra=0)

    if request.method == 'POST':
        formset = project_formset(request.POST,request.FILES)
        if formset.is_valid():
            for f in formset:
                project = f.save(commit = False)

                update_form = CreateUpdateForm(request.POST,request.FILES)
                if update_form.is_valid():
                    update = update_form.save(commit = False)
                    update.project = project
                    project.save()
                    update.save()
                else:
                    print(update_form.errors)
            return redirect('MDS_Projects')
        else:
            print(formset.errors)
    else:
        projects = Project.objects.filter(dept='Assistive Technology')
        formset = project_formset(queryset=projects)
        update_form = updateForm()
        return render(request,'MDSprojectsB.html',{'formset':formset, 'update_form':update_form})

MDSprojectsB.html

<form method="POST" enctype= multipart/form-data>
  {{ formset.management_form }}
  {% csrf_token %}
  {%for form in formset%}
    {{ form.management_form }}
    {% for hidden in form.hidden_fields %}
      {{ hidden }}
    {% endfor %}
  <div class="card border-primary mb-3" style="max-width: 85rem;">
    <div class="card-header text-primary">
       <strong>{{form.instance.description}}</strong>
    </div>
    <div class="card-body text-primary"> Project Name: {{form.description}}</div>
    <div class="card-body text-primary"> Status: {{form.status}}</div>
    <div class="card-body text-primary"> Owner: {{form.owner}}</div>
    <div class="card-body text-primary"> Priority: {{form.priority}}</div>
    <div>
        {{ update_form }}
    </div>
  </div>
  {% endfor %}
  <button class="btn btn-success btn" type="submit">Save Changes</button>
 </form>

解决方案二

您也可以对两种模型使用一种形式。由于您只需要 Update 模型的更新说明,因此您可以添加额外的表单字段来更新项目表单,因此您不需要额外的更新表单。

forms.py

class EditProjectForm(ModelForm)
    update_notes = forms.CharField(max_length=50, help_text='50 characters max.')
    class Meta:
        model = Project
        fields = ('__all__')

views.py

def mds_projects(request):
    project_formset = modelformset_factory(Project, form=EditProjectForm, extra=0)

    if request.method == 'POST':
        formset = project_formset(request.POST,request.FILES)
        if formset.is_valid():
            for f in formset:
                project = f.save(commit = False)
                update = Update.objects.create(notes=f.cleaned_data['update_notes'], project=project)
                project.save()

            return redirect('MDS_Projects')
        else:
            print(formset.errors)
    else:
        projects = Project.objects.filter(dept='Assistive Technology')
        formset = project_formset(queryset=projects)
        return render(request,'MDSprojectsB.html',{'formset':formset})

MDSprojectsB.html

<form method="POST" enctype= multipart/form-data>
  {{ formset.management_form }}
  {% csrf_token %}
  {%for form in formset%}
    {{ form.management_form }}
    {% for hidden in form.hidden_fields %}
      {{ hidden }}
    {% endfor %}
  <div class="card border-primary mb-3" style="max-width: 85rem;">
    <div class="card-header text-primary">
       <strong>{{form.instance.description}}</strong>
    </div>
    <div class="card-body text-primary"> Project Name: {{form.description}}</div>
    <div class="card-body text-primary"> Status: {{form.status}}</div>
    <div class="card-body text-primary"> Owner: {{form.owner}}</div>
    <div class="card-body text-primary"> Priority: {{form.priority}}</div>
    <div class="card-body text-primary"> Update: {{form.update_notes}}</div>
  </div>
  {% endfor %}
  <button class="btn btn-success btn" type="submit">Save Changes</button>
 </form>

附:您提供的代码违反了 python 和 django 命名约定。请尽量遵守这些约定。我已经在我的代码中修复了其中的一些问题。例如,您不应将模型命名为复数,而应为函数和变量使用驼峰命名法。

【讨论】:

  • 太棒了!非常感谢您花时间帮助我。我最终使用了解决方案 2,因为它的代码更少,而且对我来说似乎更干净。为什么这是解决方案 2 而不是 1?此外,我必须进行 2 个小改动。我使 update_notes 字段不需要,因为它抛出了一个错误,并且我还做了一个 if 语句来处理事件 update_notes 留空,否则即使是空字段也会保存。否则工作完美。再次感谢
  • 因为和你的方案比较相似,所以我就这样下单了。我更喜欢解决方案 2。我很高兴它成功了 ??
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-06-02
  • 2020-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-23
  • 1970-01-01
相关资源
最近更新 更多