Динамическое обновление значений поля в зависимости от выбора, сделанного в другом поле в Django

У меня есть две таблицы. Inventory и Invoice.

InventoryModel:

from django.db import models

class Inventory(models.Model):
  product_number = models.IntegerField(primary_key=True)
  product = models.TextField(max_length=3000, default='', blank=True, null=True)
  title = models.CharField('Title', max_length=120, default='', blank=True, unique=True)
  amount = models.IntegerField('Unit Price', default=0, blank=True, null=True)

  def __str__(self):
    return self.title

InvoiceModel:

У меня есть форма, где человек выбирает Inventory.title в line_one. Я хочу, чтобы line_one_unit_price автоматически заполнялась в соответствии с опцией, выбранной в line_one. То есть я хочу, чтобы отображалось количество этого товара.

Screenshot of the forms

Я попробовал использовать объект JSON и затем отправить его в шаблон.

views.py:

def add_invoice(request):
  form = InvoiceForm(request.POST or None)
  data = Inventory.objects.all()
  dict_obj = model_to_dict(data)
  serialized = json.dumps(dict_obj)
  total_invoices = Invoice.objects.count()
  queryset = Invoice.objects.order_by('-invoice_date')[:6]

  if form.is_valid():
    form.save()
    messages.success(request, 'Successfully Saved')
    return redirect('/invoice/list_invoice')
  context = {
    "form": form,
    "title": "New Invoice",
    "total_invoices": total_invoices,
    "queryset": queryset,
    "serialized":serialized,
  }
  return render(request, "entry.html", context)

Я не уверен, как я могу получить доступ к этому JSON файлу в javascript? Как будет называться этот JSON объект? Возможно ли получить к нему доступ в JavaScript? Как я могу использовать его для динамического обновления цены товара в формах? Спасибо.

Когда вы передаете dict_obj в ваш шаблон, вы можете получить json с помощью

{{ dict_obj|json_script:"hello-data" }}

const value = JSON.parse(document.getElementById('hello-data').textContent);

https://docs.djangoproject.com/en/4.0/ref/templates/builtins/#json-script

изменить значение в зависимости от выбранного элемента

const data = {
    "apple": 2.3,
    "orange": 1.7,
    
}

document.getElementById('inventory_item').onchange = function() {
    document.getElementById('price').value = data[this.value];
};
<select name="InventoryDropdown" id="inventory_item">
<option value="" selected disabled>---</option>
<option value="apple">apple</option>
<option value="orange">orange</option>
</select>
<input type="text" id="price" >

если я правильно понял, вы получаете pk инвентаря в этой строке

var line_one=document.getElementById('id_line_one').value

поэтому вам нужно выполнить итерацию по json, чтобы найти его - я проверил это с вашим распечатанным JSON-файлом

function getDictEntryByPk(dict_list, pk) {
   for (let i=0; i < dict_list.length; i++) {
       if (dict_list[i].pk == pk) {
           return dict_list[i]
       }
   }
}

и использовать его следующим образом:

var line_one=document.getElementById('id_line_one').value;
var line_one_data = getDictEntryByPk(data, line_one);
document.getElementById('id_line_one_unit_price').value = line_one_data.fields.amount

РЕДИТ: то же самое с меньшим количеством кода:

function getDictEntryByPk(dict_list, pk) {
    return dict_list.find(element => element.pk == pk);
}

Простой альтернативой может быть переопределение метода Inventory __str__ для включения цены за единицу, так что выпадающий список станет, например, 'Inventory #1 - ₹500'. После этого вам не нужно беспокоиться о JS, JSON или обновлении суммы. Общая сумма может обновляться каждый раз, когда форма отправляется с количеством. В противном случае вам понадобится JS для получения цены единицы товара и вычисления общей цены с учетом количества.

Кроме того, в ваших моделях есть строки, вручную добавленные в счет-фактуру - т.е. строка_один, строка_два и т.д. - это не лучший способ структурирования моделей и данных. Вы должны добавить промежуточную модель под названием 'InvoiceLine' или что-то подобное, которая может обрабатывать любое количество строк счета-фактуры и соединяет с помощью FKs ваши модели инвентаризации и счета-фактуры. Причина, по которой это особенно важно, заключается в том, что в настоящее время все ваши строки имеют models.CASCADE в качестве опции on_delete, что означает, что счет-фактура с десятью строками может быть полностью удален, даже если будет удалена только одна из ваших моделей инвентаря с FK-связью!

Я выяснил, как добиться этой функциональности. Я хотел бы отдать должное одному человеку, но на самом деле это комбинация ответов многих людей.

в views.py, который возвращает HTML страницу, где я хочу получить эту функциональность, я написал этот код, Он возвращает объекты Product в HTML файл:

model_data=Inventory.objects.values_list('product_number','amount')
data=[model for model in model_data.values()]
context = {
    "data": data,
}
return render(request, "entry.html", context)

В entry.html я получаю доступ к данным, используя: {{ data|json_script:"hello-data" }}
Тогда я получаю следующие данные:

[{"product_number": 1, "product": "Laptop", "title": "Lenovo", "amount": 50000}, {"product_number": 2, "product": "Single Table Tennis Ball", "title": "Table Tennis Ball Share", "amount": 4}]

В entry.html я использовал немного javascript:

<script type="text/javascript">
    var data = JSON.parse(document.getElementById('hello-data').textContent);
    document.getElementById('id_line_one').onchange = function(event){
        var data1 = data.find(({product_number}) => product_number == event.target.value);
        document.getElementById('id_line_one_unit_price').value = data1 && data1.amount ? data1.amount : 0;
};

Итак, я разбираю данные JSON, а затем, когда пользователь нажимает на выпадающее меню, id которого id_line_one, я проверяю, совпадает ли возвращаемое число (т.е. номер_продукта) с любым product_number, присутствующим в переменной data. и затем я изменяю сумму соответствующего поля.

Ссылка: https://stackoverflow.com/a/72923853/9350154

Вернуться на верх