如何为Django ModelForm创建子表单

时间:2018-04-26 19:46:08

标签: django modelform

我在使用ModelForm添加ManyToMany字段时遇到问题,问题是我不知道如何创建子表单以将此数据添加到我的主表单。我想在单击按钮时创建要保存的子表单,并且我希望选择保存的数据以在主表单中使用。

我的模特

class Teste(models.Model):

   name = models.CharField(max_length=255)
   parent_institution_name = models.CharField(max_length=255)
   laboratory_departament = models.CharField(max_length=255, null=True, 
   blank=True, verbose_name="Laboratório")
   cep = models.CharField(max_length=255, verbose_name="Cep")
   cnpj = models.CharField(max_length=255, verbose_name="CNPJ")
   lat = models.FloatField(blank=True, null=True)
   lng = models.FloatField(blank=True, null=True)
   institution_name = models.CharField(max_length=255, null=False, 
   verbose_name="Nome da instituição")
   parent_institution_name = models.CharField(max_length=255, blank=True, 
   null=True, verbose_name="Nome da instituição vinculada")
   coordinator = models.CharField(max_length=255, verbose_name="Pessoa 
   Responsavel")
   email = models.CharField(max_length=255, verbose_name="E-mail")
   website = models.CharField(max_length=255, blank=True, null=True, 
   verbose_name="Website")
   rad_operating_time = models.IntegerField(verbose_name="Tempo de atuação 
   ")
   research_line = models.ManyToManyField('researcher.ResearchLines')

我的ModelForm     class TestForm(forms.ModelForm):         class Meta:

        model = Test
        exclude = ('employee_number', ' revenues', 'filter_grade', 'grade', ' 
        knowledge_grade',
    'application_grade', 'ie_grade', ' ia_grade', 'final_grade', 'inactive', 'last_coordinator_access', ' hr_count',
    'hr_returned', ' match_hr_count', 'general_grade', 'lat', 'lng'
    'tokens', 'iso_certification', 'other_certification', 'researchers', 'thematic_network',
    )


    widgets ={
        'name':forms.TextInput(attrs={
            'class':'form-control',
            'placeholder': 'Nome da UBC'
        }),
        'parent_institution_name': forms.TextInput(attrs={
            'class':'form-control',
            'placeholder':'Nome da Instituição à qual a UBC é vinculada'
        }),
        'laboratory_departament': forms.TextInput(attrs={
            'class':'form-control',
            'placeholder':'Laboratório/Departamento'
        }),
        'cep': forms.TextInput(attrs={
            'class':'form-control',
            'placeholder':'CEP'
        }),
        'cnpj': forms.TextInput(attrs={
            'class':'form-control',
            'placeholder':'CNPJ'
        }),
        'institution_name': forms.TextInput(attrs={
            'class':'form-control',
            'placeholder':'Nome da instituição'
        }),
        'coordinator': forms.TextInput(attrs={
            'class':'form-control',
            'placeholder':'Pessoa Responsável'

        }),
        'email': forms.TextInput(attrs={
            'class':'form-control',
            'placeholder':'E-mail'
        }),
        'website': forms.TextInput(attrs={
            'class':'form-control',
            'placeholder':'Website'
        }),
        'rad_operating_time': forms.TextInput(attrs={
            'class':'form-control',
            'placeholder':'Tempo de atuação em projetos de P&D+I'
        }),
        'phone': forms.TextInput(attrs={
            'class':'form-control',
            'placeholder': 'Telefone'
        }),
        'partner_category': forms.RadioSelect(),

        'main_product':forms.CheckboxSelectMultiple( attrs={
            'type':'checkbox'
        }),        
    }

我的表单如何显示,最后一个输入显示子表单添加数据的位置
enter image description here

2 个答案:

答案 0 :(得分:3)

这是我使用内联表单集的示例,它实际上将两个表单组合成一个显示的表单。 formset是服务形式,并且打孔形成我的意图是打孔是“形式中的形式”。

here

VIEWS.PY(最具影响力的部分)

def reportcreateview(request):
    if request.method == 'POST':
        reportform = ServiceReportCreateForm(request.POST)
        if reportform.is_valid():
            report = reportform.save(commit=False)
            report.reported_by = request.user
            punchesform = PunchesFormSet(request.POST, request.FILES, instance=report)
            if punchesform.is_valid():
                report.save()
                punchesform.save()
            return redirect('service:update-report', pk=report.pk)
    else:
        punchesform = PunchesFormSet()
        reportform = ServiceReportCreateForm()
        reportform.reported_by = request.user
    context = {
        'report': reportform,
        'punches': punchesform,
    }
    return render(request, 'service/report-create.html', context)

<强> FORMS.PY

from django import forms
from django.forms.models import inlineformset_factory, BaseInlineFormSet
from .models import ServiceReportModel, ReportPunchesModel, ServiceRequestModel


class ServiceReportCreateForm(forms.ModelForm):

    class Meta:
        model = ServiceReportModel
        fields = [
            'site',
            'invoiced',
            'paid',
            'request_number',
            'equipment',
            'report_reason',
            'actions_taken',
            'recommendations',
        ]
        widgets = {
            'site': forms.Select(attrs={
                'class': 'form-control',
                'id': 'inputSite',
            }),
            'invoiced': forms.CheckboxInput(attrs={
                'class': 'form-control',
            }),
            'paid': forms.CheckboxInput(attrs={
                'class': 'form-control',
            }),
            'request_number': forms.Select(attrs={
                'class': 'form-control',
                'id': 'inputRequest',
            }),
            'equipment': forms.Select(attrs={
                'class': 'form-control',
                'id': 'inputEquipment',
            }),
            'report_reason': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': 'Enter Reason for Service Report'}),
            'actions_taken': forms.Textarea(attrs={
                'class': 'form-control',
                'placeholder': 'To the best of your abilities, list all actions taken during service.  Please include'
                'dates, times, and equipment names'}),
            'recommendations': forms.Textarea(attrs={
                'class': 'form-control',
                'placeholder': 'If any recommendations were made to the customer that'
                               'require follow-up itemize them here...'}),
        }

        def __init__(self, *args, **kwargs):
            super(ServiceReportCreateForm, self).__init__(*args, **kwargs)
            self.fields['request_number'].required = False


class ServiceReportUpdateForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super(ServiceReportUpdateForm, self).__init__(*args, **kwargs)
        instance = getattr(self, 'instance', None)
        if instance and instance.pk:
            self.fields['request_number'].required = False
            self.fields['report_reason'].widget.attrs['readonly'] = True

    class Meta:
        model = ServiceReportModel
        fields = [
            'invoiced',
            'paid',
            'request_number',
            'updated_by',
            'report_reason',
            'actions_taken',
            'recommendations',
        ]
        widgets = {
            'invoiced': forms.CheckboxInput(attrs={
                'class': 'form-control',
            }),
            'paid': forms.CheckboxInput(attrs={
                'class': 'form-control',
            }),
            'request_number': forms.Select(attrs={
                'class': 'form-control',
                'id': 'inputRequest',
            }),
            'updated_by': forms.Select(attrs={
                'class': 'form-control',
                'id': 'inputReporter',
            }),
            'report_reason': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': 'Enter Reason for Service Report'}),
            'actions_taken': forms.Textarea(attrs={
                'class': 'form-control',
                'placeholder': 'To the best of your abilities, list all actions taken during service.  Please include' +
                'dates, times, and equipment names'}),
            'recommendations': forms.Textarea(attrs={
                'class': 'form-control',
                'placeholder': 'If any recommendations were made to the customer that'
                               'require follow-up itemize them here...'}),
        }


PunchesFormSet = inlineformset_factory(
    ServiceReportModel,
    ReportPunchesModel,
    fields=('date',
            'time_in',
            'time_out',
            ),
    widgets={
            'date': forms.DateInput(attrs={
                'type': 'date'
            }),
            'time_in': forms.TimeInput(attrs={
                'type': 'time'
            }),
            'time_out': forms.TimeInput(attrs={
                'type': 'time'
            })},
    extra=1,
    can_order=True
)

<强> MODELS.PY

class ServiceReportModel(ServiceParent):
    report_number = models.UUIDField(
        primary_key=True, default=uuid.uuid4, editable=False)
    invoiced = models.BooleanField(default=False, null=False)
    paid = models.BooleanField(default=False, null=False)
    request_number = models.ForeignKey(ServiceRequestModel,
                                       on_delete=models.PROTECT,
                                       null=True,
                                       blank=True,
                                       related_name='s_report_number'
                                       )
    reported_by = models.ForeignKey(
        main_models.MyUser, related_name='reporter', on_delete=models.PROTECT)
    reported_date = models.DateTimeField(auto_now_add=True)
    report_reason = models.CharField(max_length=255, null=True)
    actions_taken = models.TextField(null=False, blank=False)
    recommendations = models.TextField(null=True, blank=True)

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

    def __str__(self):
        return '%s - %s, %s' % (self.site.company,
                                self.reported_date.strftime('%d %B %Y'),
                                self.equipment.name
                                )

    class Meta:
        ordering = ['reported_date', 'updated_date']
        verbose_name = 'Service Report'
        verbose_name_plural = 'Service Reports'


class ReportPunchesModel(models.Model):
    punch_id = models.UUIDField(
        primary_key=True, default=uuid.uuid4, editable=False)
    added = models.DateTimeField(auto_now_add=True)
    report = models.ForeignKey(ServiceReportModel, on_delete=models.CASCADE)
    date = models.DateField(blank=True, null=True)
    time_in = models.TimeField(blank=True, null=True)
    time_out = models.TimeField(blank=True, null=True)

    def __str__(self):
        return '%s - %s' % (self.time_in,
                            self.time_out
                            )

    class Meta:
        ordering = ['added', 'date', 'time_in']
        verbose_name = 'Report Punches'
        verbose_name_plural = verbose_name

答案 1 :(得分:0)

Jaberwocky这是我的代码,我必须提前告知我的代码我还在学习

class Ubc(models.Model):
    """ Table Ubc """
    name = models.CharField(verbose_name="Nome da instituição", max_length=255, null=False)
    laboratory_departament = models.CharField(max_length=255, null=True, blank=True, verbose_name="Laboratório")
    cep = models.CharField(max_length=255, verbose_name="Cep", null=True)
    cnpj = models.CharField(max_length=255, verbose_name="CNPJ", null=True)
    lat = models.FloatField(blank=True, null=True)
    lng = models.FloatField(blank=True, null=True)
    street = models.CharField(max_length=255, verbose_name="Endereco", null=True, blank=True)
    uf = models.CharField(max_length=255, verbose_name="UF", null=True, blank=True)
    city = models.CharField(max_length=255, verbose_name="City", null=True, blank=True)
    parent_institution_name = models.CharField(verbose_name="Nome da instituição vinculada", max_length=255, blank=True, null=True)
    coordinator = models.CharField(max_length=255, verbose_name="Pessoa Responsavel")
    email = models.CharField(max_length=255, verbose_name="E-mail")
    website = models.CharField(max_length=255, blank=True, null=True, verbose_name="Website")
    rad_operating_time = models.IntegerField(verbose_name="Tempo de atuação em projetos de P&D+I")

    phone = models.CharField(max_length=255, verbose_name="Telefone", null=True)
    inactive = models.NullBooleanField(verbose_name="Inativo", default=False, null=True)
    partner_category = models.ForeignKey('PartnerSubCategory', on_delete=models.CASCADE)
    parent = models.ForeignKey('Company', blank=True, null=True, on_delete=models.CASCADE)
    general_grade = models.ForeignKey('GeneralGrade', blank=True, null=True, on_delete=models.CASCADE)
    main_product = models.ManyToManyField('MainProductUbc', verbose_name="Qual o tipo de produto e/ou servico que a UBC fornece (produto, processo, mudanca organizacional)")
    tokens = models.ManyToManyField('ubc.Token', blank=True, related_name='tokens')
    activity_branch = models.ForeignKey('ActivityBranch', verbose_name="Ramo de Atividade (CNAE)", null=True, on_delete=models.CASCADE)      
    researchers = models.ManyToManyField('researcher.Researcher', related_name='researchers', through='researcher.ResearcherUbc', blank=True)    
    research_line = models.ManyToManyField('researcher.ResearchLines',related_name='ubc_lines', blank=True)  


class ResearchLines(models.Model):
    title = models.CharField(verbose_name="Descrição da Linha de Pesquisa", max_length=255, blank=True, null=True)
    ubc = models.ForeignKey('ubc.Ubc', on_delete=models.CASCADE)
    created = models.DateTimeField(auto_now_add=True)
    updtaed = models.DateTimeField(auto_now=True)

    class Meta:
        verbose_name_plural = 'Research Line'

    def __str__(self):
        return self.title

views.py

def ubc_register(request):
    if request.method == "POST":
        form = UbcForm(request.POST or None)
        if form.is_valid():
            form = form.save(commit=False)
            formset = LinesFormSet(request.POST, request.FILES, instance=form)
            if formset.is_valid():
                form.save()
                formset.save()         
            return HttpResponseRedirect(reverse('index'))
    else:
        form = UbcForm(prefix="form")
        formset = LinesFormSet(prefix="formset")
        context = {
            'form':form,
            'formset':formset
        }
        return render(request, 'accounts/ubc_form.html', context)

forms.py

class UbcForm(forms.ModelForm):


    class Meta:

        research_line = forms.ModelMultipleChoiceField(queryset=ResearchLines.objects.all())

        model = Ubc
        exclude = ('employee_number', ' revenues', 'filter_grade', 'grade', 
        ' knowledge_grade',
        'application_grade', 'ie_grade', ' ia_grade', 'final_grade', 
        'inactive', 'last_coordinator_access', ' hr_count',
        'hr_returned', ' match_hr_count', 'general_grade', 'lat', 'lng'
        'tokens', 'iso_certification', 'other_certification', 'researchers', 
        'thematic_network',
     )


        widgets ={
            'name':forms.TextInput(attrs={
            'class':'form-control',
            'placeholder': 'Nome da UBC'
        }),
            'parent_institution_name': forms.TextInput(attrs={
            'class':'form-control',
            'placeholder':'Nome da Instituição à qual a UBC é vinculada'
        }),
            'laboratory_departament': forms.TextInput(attrs={
            'class':'form-control',
            'placeholder':'Laboratório/Departamento'
        }),            
            'cnpj': forms.TextInput(attrs={
            'class':'form-control',
            'placeholder':'CNPJ'
        }),
            'institution_name': forms.TextInput(attrs={
            'class':'form-control',
            'placeholder':'Nome da instituição'
        }),
            'coordinator': forms.TextInput(attrs={
            'class':'form-control',
            'placeholder':'Pessoa Responsável'

        }),
            'email': forms.TextInput(attrs={
            'class':'form-control',
            'placeholder':'E-mail'
        }),
            'website': forms.TextInput(attrs={
            'class':'form-control',
            'placeholder':'Website'
        }),
            'rad_operating_time': forms.NumberInput(attrs={
            'class':'form-control',
            'placeholder':'Tempo de atuação em projetos de P&D+I'
        }),
            'phone': forms.TextInput(attrs={
            'class':'form-control',
            'placeholder': 'Telefone'
        }),
            'partner_category': forms.RadioSelect(),

            'main_product':forms.CheckboxSelectMultiple( attrs={
            'type':'checkbox'
        }),   
            'activity_branch':forms.Select( attrs={
            'class':'form-control'
        }),
            'research_line':forms.TextInput(attrs={
            'class':'form-control'
        }),

            'cep': forms.TextInput(attrs={
            'class':'form-control',
            'placeholder':'CEP'
        }),
            'street': forms.TextInput(attrs={
            'class':'form-control',
            'placeholder':'Endereço'
        }),
            'city': forms.TextInput(attrs={
            'class':'form-control',
            'placeholder':'Cidade'
        }),
            'uf': forms.TextInput(attrs={
            'class':'form-control',
            'placeholder':'UF'
        }),


    }

class ResearchLineForm(forms.ModelForm):
    class Meta:
        model = ResearchLines
        fields = ('title', )

        widgets = {
            'title':forms.TextInput(attrs={
            'class':'form-control'
        })
    }

class AddressForm(forms.ModelForm):
    model = Address
    fields = '__all__'


LinesFormSet = inlineformset_factory(
    Ubc,
    ResearchLines,
    fields=('title', ),
    extra=1,
    widgets = {
        'title':forms.TextInput(attrs={
            'class':'form-control'
    })
}
)

在我的form.html里面的formset标签和来自django-dynamic-formset的脚本来生成新表单

{{formset.management_form}}
{% for form in formset %}                
     <div class="link-formset">
         {{ form }}                                                           
     </div>
 {% endfor %}


<script>
    $('.link-formset').formset({
        addText: 'add link',
        deleteText: 'remove'
    });
</script>