模型Formset和常规ModelForm在同一模板中?

问题描述

我有两种型号:

Project:

class Project(Model):
    
    name = CharField(max_length=50)
    members = ManyToManyField("accounts.User",through='ProjectUser')
    organization = ForeignKey(Organization,related_name="projects",on_delete=CASCADE)

    def __str__(self):
        return self.name

Task:

class Task(Model):
    task = CharField(max_length=100)
    project = ForeignKey(Project,on_delete=CASCADE)

    class Meta:
        db_table = 'task'

我有一个UpdateView班:

class ProjectUpdateView(UpdateView):
    form_class = ProjectUpdateForm
    template_name = 'projects/project_edit.html'
    success_url = reverse_lazy('projects:list')

我如何允许用户(通过内嵌表单集)在他们编辑Project实例的页面添加任务?

例如一种统一的表单,用户可以在一个地方编辑Project name,并添加/删除Task实例

解决方法

表单/表单集:

首先,为您的任务模型创建一个表单和一个表单集

class TaskForm(ModelForm):
    class Meta:
        model = Task
        fields = ['task']

    def __init__(self,*args,**kwargs):
        super(TaskForm,self).__init__(*args,**kwargs)



class TaskBaseFormSet(BaseInlineFormSet):
    def __init__(self,**kwargs):
        super(TaskBaseFormSet,**kwargs)



TaskFormset = inlineformset_factory(
    Project,# parent_model
    Task,# model
    form=TaskForm,formset=TaskBaseFormSet
)

或者如果您不需要TaskForm类,那么创建TaskFormset所需要做的就是这个

TaskFormset = inlineformset_factory(Project,Task,fields=('task',))

查看:

我看到您正在为视图使用UpdateView类,因此您可以执行此操作以在context_data中获取TaskFormset,因此现在您可以在您在自己的“ template_name”属性中声明的模板中使用TaskFormset UpdateView类

def get_context_data(self,**kwargs):
    context = super().get_context_data(**kwargs)

    if self.request.POST:
        context['task_formset'] = forms.TaskFormset(self.request.POST)
    else:
        context['task_formset'] = forms.TaskFormset()


    return context

# In the form_valid method of your UpdateView class you can validate the data 
# and assign the Project instance to all the tasks that were create by the formsets

def form_valid(self,form):

     task_formset = context['task_formset']

     # you can validate formset data like this
     if not task_formset.is_valid():
        return self.form_invalid(form)


     project = form.save()
     # Here you assign the Project instance to the Tasks
     task_formset.instance = project
     task_formset.save()

     return super().form_valid(form)

模板:

现在您所要做的就是使用循环从表单集中打印management_form和每个表单,如下面的代码所示

<form method="post">

    <!-- Your ProjectUpdateForm form here... -->

    {{ task_formset.management_form }}
    <table>
        {% for form in task_formset %}
        {{ form }}
        {% endfor %}
    </table>
</form>

希望这会有所帮助!有一些指向官方Django文档的链接,您可能会发现它们有用:

https://docs.djangoproject.com/en/3.1/topics/forms/formsets/#using-a-formset-in-views-and-templates

https://docs.djangoproject.com/en/3.1/topics/forms/modelforms/#inline-formsets

https://docs.djangoproject.com/en/3.1/ref/forms/models/#inlineformset-factory