Django Modelform Crispy Form генерирует несколько повторяющихся запросов - PullRequest
0 голосов
/ 13 февраля 2020

Model.py

class Tenancy(CreationModificationDateMixin):
    TENANCY_STATUS_CHOICE = (
        ( 1 , "ACTIVE"),
        ( 2 , "LEGAL"),
        ( 3 , "EXPIRED"),
        ( 4 , "INACTIVE"),
    )
    outlet = models.ForeignKey(Outlet, on_delete=models.PROTECT)
    tenant = models.ForeignKey(Company, related_name="tenant_tenancies",on_delete=models.PROTECT)
    landlord = models.ForeignKey(Company, related_name="landlord_tenancies", on_delete=models.PROTECT)
    stampdutyno = models.CharField(_("Stamp Duty No."), max_length = 13, unique=True, validators=[RegexValidator(regex='^\d{13}$', message="Stamp Duty No. has to be 13 digits", code="nomatch")])
    stallno = models.ManyToManyField(OperatingStall)
    cuisine = models.CharField(_("Cuisine"), max_length=50)
    business_name = models.CharField(_("Business Name"), max_length=50, null=True, blank=True)
    startdate = models.DateField(_("Start Date"))
    enddate = models.DateField(_("End Date"))
    gurantorname = models.CharField(_("Gurantor's Name"), max_length=50)
    gurantoraddress = models.CharField(_("Gurantor's Address"), max_length=50)
    postal_code = models.CharField(_("Postal Code"), max_length = 6, validators=[RegexValidator(regex='^\d{6}$', message="Postal Code has to be 6 digits", code="nomatch")])
    gurantorNRIC = models.CharField(_("Gurantor's NRIC"), max_length=9)
    status = models.PositiveIntegerField(_("Status"), choices=TENANCY_STATUS_CHOICE, default=1)
    yearly_insurance = models.BooleanField(_("Bill Yearly Insurance?"), default=True)

    class Meta:
        verbose_name = 'Tenancy'
        verbose_name_plural = 'Tenancies'

    def __str__(self):
        stall = " & ".join(str(stall) for stall in self.stallno.all())
        return f"{stall} - {self.tenant.name} | ({self.startdate} to {self.enddate})"

class TenancyChargeType(CreationModificationDateMixin):
    BILLING_CYCLE = (
        ( 1 , "INITIAL"), #Have to bill once entered into system
        ( 2 , "MONTHLY"), #Bill Monthly
        ( 3 , "END OF MONTH"), #Bill End of Month
        ( 4 , "YEARLY"), #Bill Yearly
        ( 5 , "AD HOC"), #Bill AD HOC
    )
    name = models.CharField(_("Charges Name"), max_length=50)
    account_no = models.CharField(_("Eclink Account No."), max_length = 11, validators=[RegexValidator(regex='^\d{11}$', message="Account No. has to be 11 digits", code="nomatch")])
    eclink_name = models.CharField(_("Eclink A/c Name"), max_length=50)
    billingcycle = models.PositiveIntegerField(_("Billing Cycle"), choices=BILLING_CYCLE)
    is_prorated = models.BooleanField(_("Is Prorated?"), default=True)
    is_gst = models.BooleanField(_("Is GST?"), default=True)
    is_addinformation = models.BooleanField(_("Extra Info?"), default=False)

    class Meta:
        verbose_name = 'Tenancy Charge Type'
        verbose_name_plural = 'Tenancy Charges Type'

    def __str__(self):
        return self.name

class TenancyCharge(CreationModificationDateMixin):
    tenancy = models.ForeignKey("Tenancy", related_name="tenancycharges", on_delete=models.PROTECT)
    version = models.CharField(_("Version"), max_length=4) #For different version of batch
    charge = models.ForeignKey("TenancyChargeType", on_delete=models.PROTECT)
    description = models.CharField(_("Description"), max_length=50, blank=True)
    amount = models.DecimalField(max_digits=8, decimal_places=3)
    startdate = models.DateField(_("Start Date"))
    enddate = models.DateField(_("End Date"))
    is_active = models.BooleanField(_("Active Status"), default=True)

    def __str__(self):
        return f"{self.tenancy}-{self.version} | {self.charge} - {self.amount} | ({self.startdate} to {self.enddate})"

Form.py

class TenancyForm(forms.ModelForm):
    DF_updatefield =('outlet','stallno','tenant','landlord','stampdutyno','startdate')
    DF_detailfield =('outlet', 'stallno','tenant','landlord','status',
        'stampdutyno','startdate','enddate','cuisine','business_name','gurantorNRIC',
        'gurantoraddress','postal_code','gurantorname','yearly_insurance'
        )
    DF_renewfield =('outlet','stallno','tenant','landlord',)
    class Meta:
        model = Tenancy
        exclude = ['created','updated']

    def __init__(self, disabled_form=False, fields=None, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.helper = helper.FormHelper()
        self.helper.form_method = "POST"
        self.helper.layout = Layout(
                Fieldset(_("Tenant Detail:"), Row(
                            Column(Field('outlet'), css_class='col-md-1 mb-0'),
                            Column(Field('stallno', css_class='select2-multiple'), css_class='col-md-2 mb-0'),
                            Column(Field('tenant'), css_class='col-md-4 mb-0'),
                            Column(Field('landlord'), css_class='col-md-5 mb-0'),
                        ),
                    ),
                Fieldset(_(""), Row(
                            Column(Field('stampdutyno'), css_class='col-md-2 mb-0'),
                            Column(bootstrap.PrependedText('startdate','<i class="fa fa-calendar"></i>'), css_class='col-md-2 mb-0'),
                            Column(bootstrap.PrependedText('enddate','<i class="fa fa-calendar"></i>'), css_class='col-md-2 mb-0'),
                            Column(Field('cuisine'), css_class='col-md-2 mb-0'),
                            Column(Field('business_name'), css_class='col-md-4 mb-0'),
                        ),
                    ),
                Fieldset(_(""), Row(
                            Column(Field('gurantorname'), css_class='col-md-3 mb-0'),
                            Column(Field('gurantorNRIC'), css_class='col-md-2 mb-0'),
                            Column(bootstrap.PrependedText('gurantoraddress','<i class="fa fa-address-card"></i>'), css_class='col-md-5 mb-0'),
                            Column(bootstrap.PrependedText('postal_code','<i class="fa fa-address-card-o"></i>'), css_class='col-md-2 mb-0'),
                        ),
                        Row(
                            Column(Field('status'), css_class='col-md-6 mb-0'),
                            Column(Field('yearly_insurance'), css_class="col-md-6 mb-0"),
                        ),
                    ),

            )
        if kwargs.get('instance') is not None:
            if disabled_form:
                if fields == "update":
                    self.helper.layout.append(HTML("""<p><strong>Fill in the charges amount below, if no such charges please remove before save</strong></p>"""))
                    self.helper.layout.append(Formset('tenanycharges'))
                    self.helper.layout.append(bootstrap.FormActions(Submit("submit",_("Save")))) 
                    for field in self.DF_updatefield:
                        self.fields[field].widget.attrs['disabled'] = True
                if fields == "detail":
                    for field in self.DF_detailfield:
                        self.fields[field].widget.attrs['disabled'] = True
        else:
            if disabled_form:
                if fields == "renew":
                        self.helper.layout.append(bootstrap.FormActions(Submit("submit",_("Save")))) 
                        for field in self.DF_renewfield:
                            self.fields[field].widget.attrs['disabled'] = True
            self.fields['outlet'].widget.attrs['disabled'] = True
            self.fields['landlord'].widget.attrs['disabled'] = True
            self.helper.layout.append(HTML("""<p><strong>Fill in the charges amount below, if no such charges please remove before save</strong></p>"""))
            self.helper.layout.append(Formset('tenanycharges'))
            self.helper.layout.append(bootstrap.FormActions(Submit("submit",_("Save")))) 

View.py

class TenancyCreate(CreateView):
    model = Tenancy
    form_class = TenancyForm
    template_name = 'tenancy/tenancy_form.html'
    success_url = reverse_lazy('tenancy-list')
    excluded_tclist = ['penalty', 'management fee', 'utility', 'rebate']
    list_of_tc = TenancyChargeType.objects.only('name').exclude(name__contains='penalty').exclude(name__contains='management fee').exclude(name__contains='utility').exclude(name__contains='rebate').defer('created', 'updated')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        outlet = Outlet.objects.get(id=self.kwargs.get('outlet_pk'))
        form = TenancyForm(initial={'outlet':outlet,'landlord':1},  disabled_form=True)
        form.fields['outlet'].queryset = Outlet.objects.filter(id=outlet.id)
        form.fields['stallno'].queryset = OperatingStall.objects.filter(outlet=outlet, is_own=False)
        form.fields['tenant'].queryset = Company.objects.filter(company_code__contains=str(outlet.outlet_code)[1:]).exclude(name__contains="F M Food Court")
        form.fields['landlord'].queryset = Company.objects.filter(name__contains="F M Food Court")
        initial_list = [{'charge':x.id } for x in self.list_of_tc]
        formset = TenancyChargeInlineFormSet(initial=initial_list) 
        formset.extra = self.list_of_tc.count()
        if self.request.POST:
            context['tenanycharges'] = TenancyChargeInlineFormSet(self.request.POST)
        else:
            context['form'] = form
            context['tenanycharges'] = formset
        return context

    def form_valid(self, form):
        context = self.get_context_data()
        tenanycharges = context['tenanycharges']
        with transaction.atomic():
            if tenanycharges.is_valid():
                self.object = form.save()
                tenanycharges.instance = self.object
                ftenancycharges = tenanycharges.save()
                for tc in ftenancycharges:
                    tc.version = 'V001'
                    tc.save()
                messages.success(self.request, f"{self.object} created") 
        return super().form_valid(form)

При создании createview в django версии 2.1.15 инструмент django -debug отразил несколько повторяющихся запросов и длительное время ожидания.

Кажется, проблема заключается в дублировании запросов и 2-х подобных запросов использует больше всего времени.

Просто интересно, как я могу оптимизировать это, столкнулись с той же проблемой с другими формами (используя хрустящие формы).

enter image description here

...