How to create a subform for Django ModelForm

半世苍凉 提交于 2020-05-14 07:09:33

问题


I'm having a problem to add a ManyToMany field with ModelForm, the problem is that I don't know how to create a subform to add this data to my primary form. I want to create a subform to be saved when I click a button, and I want the data that was saved to be selected to use in the primary form.

my model

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')

my 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'
        }),        
    }

How my form looks, the last input shows where the subform goes to add data


回答1:


Here is an example where I use inline formsets, which is in essence combining two forms into one displayed form. The formset is the service form, and the punches form where my intention is that the punches are the "form within the form".

VIEWS.PY (the most influential part)

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



回答2:


Jaberwocky Here is my code, I have to say sorry in advance for my code I still learning

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'
    })
}
)

inside of my form.html the formset tag and the script from django-dynamic-formset to generate the new form

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


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


来源:https://stackoverflow.com/questions/50050809/how-to-create-a-subform-for-django-modelform

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!