Django : Получение (модели) значения __str__ foreignkey (текст) вместо его ID в результате ajax-поиска

Я использую JS для поиска товаров таким образом :

models.py (summary)

class Produit(models.Model):
     famille = models.ForeignKey(Famille, on_delete=SET_NULL, null=True)
     sku = models.CharField(max_length=100, unique=True)
     nom = models.CharField(max_length=250)
     fournisseur = models.ForeignKey(
              Supplier, on_delete=models.SET_NULL, default=12, null=True)
     qty = models.IntegerField()
     mini = models.IntegerField()

[...]

Например, для Famille, я установил str на :

class Famille(models.Model):
   nom = models.CharField(max_length=50)
   [...]

def __str__(self):
    return self.nom

В моем шаблоне есть поле поиска, которое прослушивается моим JS кодом

product_search.js

const searchField = document.querySelector("#searchField");
const tableBody = document.querySelector('.table-body');
const appTable = document.querySelector('.app-table');
const tableOutput = document.querySelector('.table-output');
tableOutput.style.display = 'none'

searchField.addEventListener('keyup', (e) => {
   const searchValue = e.target.value;

   if (searchValue.trim().length > 2) {
       tableBody.innerHTML = '';
       fetch("search-product2", {
           body: JSON.stringify({ searchText: searchValue }),
           method: "POST",
       })
        .then((res) => res.json())
        .then((data) => {
            tableOutput.style.display = 'block'
            appTable.style.display = "none";

            if (data.length === 0) {
                tableOutput.innerHTML = '<h3>Aucun résultat.</h3>';

            } else {
                console.log("data", data);
                data.forEach((item) => {
                    tableBody.innerHTML += `
                    <tr>
                        <th><a href="{% url 'product-update' ${item.id} %}">${item.sku}</a></th>
                        <td>${item.etat_id}</td>
                        <td>${item.nom}</td>
                        <td>${item.famille}</td>
                        <td>${item.mageid}</td>
                        <td>${item.adresse}</td>
                        <td>${item.fournisseur}</td>
                        [...]
                        <td>${item.cau_cli}</td>
                        <td>${item.maxsst2}</td>
                    </tr>
                    `;
                });
            }

          });
  } else {
      console.log('longueur de terme de recherche insuffisante');
      tableOutput.style.display = "none";
      appTable.style.display = "block";
  }

});

Код JS называет это

view.py

def search_product2(request):
  if request.method == 'POST':
     search_str = json.loads(request.body).get('searchText')

     products = Produit.objects.filter(sku__icontains=search_str) | 
          Produit.objects.filter(nom__icontains=search_str) | 
          Produit.objects.filter(mageid__icontains=search_str)

     data = products.values()
     return JsonResponse(list(data), safe=False)

Моя проблема в том, что ответ содержит Foreignkeys ID, но не значение, установленное в Models str (которое является текстовым значением)

Я думал перестроить ответ querySet, используя промежуточные запросы для извлечения нужных значений, но я хочу знать, существует ли другой "более чистый" метод.

Вы можете получить доступ к значениям связанных полей следующим образом:

 products = Produit.objects.filter(...)

 data = products.values(
     "etat__etat",
     "nom",
     "famille__nom",
     # your other fields here
 )
       
 return JsonResponse(list(data), safe=False)

Если вы не хотите, чтобы в вашем ответе были ключи с двойным подчеркиванием (например, etat__etat), вы можете назначить псевдонимы с помощью F-выражений:

 from django.db.models import F
 ...
 data = products.values(
     "nom",
     nom_d_etat=F("etat__etat"),
     nom_de_famille=F("famille__nom"),
     # your other fields here
 )

Обратите внимание, что вы не можете использовать существующее имя поля, т.е. products.values(etat=F("etat__etat") вызовет исключение:

ValueError: The annotation 'etat' conflicts with a field on the model.

Я бы также предложил вам использовать .select_related() в вашем запросе:

products = Produit.objects.filter(...).select_related("etat", "family")

Для полностью альтернативного подхода, вы можете посмотреть в Django REST Framework serializers.

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