I am a beginner in django
. I have created a form using inlineformset_factory
with jquery.formset.js
library for increasing rows. The price field uses django-smart-selects
where depending on the product selected, the available prices are populated in the price field. Everything works fine for the first row but for any other new row added, the django-smart-selects
price field no longer works. Also, when I delete the first row and re-add it, the django-smart-selects
no longer works. I want the price field to keep working on each row depending on what product is selected. Below are my codes:
urls.py
from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include
from django.conf import settings
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^chaining/', include('smart_selects.urls')),
]
models.py
class InventoryItem(models.Model):
date = models.DateField(default=timezone.now)
product_name = models.TextField(blank=False, unique=True)
sales_price = models.DecimalField(_(u'Selling Price'), decimal_places=2, max_digits=12, validators=[MinValueValidator(Decimal('0.01'))])
objects = models.Manager()
class Price(models.Model):
product_id = models.ForeignKey(InventoryItem, on_delete=models.DO_NOTHING, verbose_name='Item Name')
selling_price = models.DecimalField(_(u'Price'), decimal_places=2, max_digits=12, validators=[MinValueValidator(Decimal('0.01'))], blank=False, default=0)
objects = models.Manager()
class Invoice(models.Model):
customer_name = models.TextField(blank=False, unique=True)
objects = models.Manager()
class InvoiceItem(models.Model):
invoice = models.ForeignKey(Invoice, on_delete=models.CASCADE)
quantity = models.PositiveIntegerField(blank=False)
product_id = models.ForeignKey(InventoryItem, on_delete=models.DO_NOTHING, verbose_name='Item Name')
price = ChainedForeignKey(Price, chained_field="product_id", chained_model_field="product_id", show_all=False, auto_choose=True, sort=True, default=0)
objects = models.Manager()
forms.py
class InvoiceItemForm(ModelForm):
def __init__(self, *args, **kwargs):
super(InvoiceItemForm, self).__init__(*args, **kwargs)
instance = getattr(self, 'instance', None)
if instance and instance.id:
self.fields['price'].widget.attrs['disabled'] = 'disabled'
class Meta:
model = InvoiceItem
fields = [ 'invoice', 'quantity', 'product_id', 'price']
InvoiceItemFormset = inlineformset_factory(Invoice, InvoiceItem, form=InvoiceItemForm, extra=1, can_delete=True)
views.py
class InvoiceCreateView(SuccessMessageMixin, UserPassesTestMixin, ChainedSelectFormViewMixin, CreateView):
model = Invoice
form_class = InvoiceForm
template_name = "website1app/invoice_form.html"
success_url = reverse_lazy('invoice_list')
success_message = 'New invoice successfully added'
def get_context_data(self, **kwargs):
context = super(InvoiceCreateView, self).get_context_data(**kwargs)
if self.request.POST:
context['items'] = InvoiceItemFormset(self.request.POST, prefix='invoiceitem_set')
else:
context['items'] = InvoiceItemFormset(prefix='invoiceitem_set')
return context
def form_valid(self, form):
context = self.get_context_data()
formset = context['items']
self.object = form.save()
if self.object.id != None:
if form.is_valid() and formset.is_valid():
formset.instance = self.object
formset.save()
return super().form_valid(form)
def test_func(self):
return True
invoice_form.html
{% extends 'base_template.html' %}
{% load widget_tweaks %}
{% block title %}
{% if object %}
Update Invoice {{ object }}
{% else %}
Add New Sales Invoice
{% endif %}
{% endblock title %}
{% block main_content %}
<form method="POST" id="invoiceForm">
{% csrf_token %}
{{ form.media.js }}
{% for field in form %}
<div class="form-group">
{{ field.errors }}
{{ field.label_tag }}
{% render_field field class="form-control" %}
</div>
{% endfor %}
<div class="row" style="border-top:5px; border-top-style:outset; margin-top: 10px;">
<div class="col-sm-12 callout callout-info">
{{ items.management_form }}
<div class="text-center">PRODUCT LIST</div>
<div class="row">
<div class="col"><strong>Product</strong></div>
<div class="col"><strong>Quantity</strong></div>
<div class="col"><strong>Price</strong></div>
</div>
{% for item in items %}
<div class="form-group row items-group">
<div class="col">{{ item.product_id | add_class:"form-control"}}</div>
<div class="col">{{ item.quantity | add_class:"form-control"}}</div>
<div class="col">{{ item.price | add_class:"form-control"}}</div>
</div>
{% endfor %}
</div>
</div>
<div style="text-align: center;">
{% if object %}
<input type="submit" class="btn btn-primary" value="Update Record">
{% else %}
<input type="submit" class="btn btn-primary" value="Save">
{% endif %}
</div>
</form>
<hr>
{% endblock main_content %}
{% block custom_js %}
<script>
$(function() {
$(".items-group").formset({
prefix: '{{ items.prefix }}',
deleteText: "<div class='btn btn-danger btn-circle'><i class='fas fa-trash'></i></div>",
addText: "<div class='btn btn-success btn-circle' style='text-align: center; margin-bottom: 10px;'><i class='fas fa-plus'></i></div>",
})
})
</script>
{% endblock custom_js %}