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](https://i.stack.imgur.com/0aIQG.png)