Django:在 ajax 搜索结果中获取(模型)__str__ 外键(文本)值而不是其 ID

Django : Get (models) __str__ foreignkey (text) value instead of its ID in ajax search result

我用 JS 是这样搜索产品的:

models.py(摘要)

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)

我的问题是响应包含外键 ID,但不包含模型 str 中设置的值(这是一个文本值)

虽然我想使用中间查询重建 querySet 响应以检索所需的值,但我想知道之前是否存在另一种“更清洁”的方法。

编辑:

等待 VIEWS.PY 中更好的解决方案,我迭代每个结果并在数据库中请求“文本”。我以为它会慢很多,但是没有。

if len(data) > 0:
        for i in range(len(data)):
            etat = Etat.objects.get(pk=data[i] 
                  ['etat_id']).etat
            famille = Famille.objects.get(pk=data[i] 
                  ['famille_id']).nom
            fournisseur = Supplier.objects.get(
                pk=data[i]['fournisseur_id']).nom
            data[i]['etat_id'] = etat
            data[i]['famille_id'] = famille
            data[i]['fournisseur_id'] = fournisseur
return JsonResponse(list(data), safe=False)

我知道它不是很干净,但暂时还行

您可以像这样访问相关字段的值:

 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