You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django中通过Ajax获取外键字段值失败问题排查

我搞不懂为什么通过Ajax获取的外键值缺失,我只想通过外键ID拿到对应的名称,试了select_related()这类方法但没用。控制台日志里能看到supplier表和supplier_type表的数据,但只有supplier表的数据正常返回,supplier_type的名称没出来。我尝试用supplier_type__name也不管用,是不是我的实现哪里错了?

Ajax代码

$('.get_supplier_details').click(function (event) {

  var patient_id = $('#selected-patient').find(":selected").val();

  $.ajax({
    type: "POST",
    url: "{% url 'supplier-details' %}",
    data:{
        supplier: supplier_id
    }
    }).done(function(data){
      console.log(data);  //

    });

});

views.py代码

from main.models import (Supplier, SupplierType)

def patientdetails(request):
   supplier_id = request.POST.get('supplier')
   clients = Supplier.objects.filter(id=supplier_id ).select_related()
   qs_json = serializers.serialize('json', clients, fields=['first_name', 'middle_name', 'supplier_type__name'])

   return JsonResponse({'data': qs_json})

models.py代码

class SupplierType(models.Model):
    name = models.CharField(max_length=128, blank=True, null=True)
    is_active = models.BooleanField(default=True)
    created_at = models.DateTimeField(blank=True, null=True, auto_now_add=True)
    updated_at = models.DateTimeField(blank=True, null=True, auto_now=True)
    class Meta:
        managed = True
        db_table = 'supplier_type'

class Supplier(models.Model):
    supplier_type = models.ForeignKey(SupplierType, models.DO_NOTHING)
    first_name = models.CharField(max_length=128, blank=True, null=True)
    middle_name = models.CharField(max_length=128, blank=True, null=True)
    last_name = models.CharField(max_length=128, blank=True, null=True)
    class Meta:
        managed = True
        db_table = 'supplier'

问题原因及解决方法

核心问题

Django自带的serializers.serialize()不支持supplier_type__name这种跨模型的字段写法,它只能序列化当前模型的直接字段,外键字段默认只会返回关联对象的ID,不会自动嵌套关联模型的其他字段。另外你代码里的select_related()没指定关联模型(虽然默认会关联所有外键,但不是问题关键)。

解决方案1:手动构建序列化字典(最简单)

直接手动提取需要的字段,包括外键关联的名称,不用自带的序列化器:

修改views.py:

from main.models import Supplier
from django.http import JsonResponse

def patientdetails(request):
    supplier_id = request.POST.get('supplier')
    # 用select_related指定关联supplier_type,减少数据库查询次数
    supplier = Supplier.objects.filter(id=supplier_id).select_related('supplier_type').first()
    
    if supplier:
        # 手动组装需要的数据
        data = {
            'first_name': supplier.first_name,
            'middle_name': supplier.middle_name,
            'supplier_type_name': supplier.supplier_type.name
        }
    else:
        data = {}
    
    return JsonResponse({'data': data})

解决方案2:用Django REST Framework序列化器(更规范)

如果项目需要更复杂的序列化场景,推荐用DRF的序列化类来处理关联字段:

  1. 先安装DRF(如果没装):
pip install djangorestframework
  1. 在settings.py里添加rest_framework到INSTALLED_APPS:
INSTALLED_APPS = [
    # ...其他应用
    'rest_framework',
]
  1. 创建serializers.py:
from rest_framework import serializers
from main.models import Supplier, SupplierType

class SupplierTypeSerializer(serializers.ModelSerializer):
    class Meta:
        model = SupplierType
        fields = ['name']

class SupplierSerializer(serializers.ModelSerializer):
    # 嵌套关联模型的序列化器
    supplier_type = SupplierTypeSerializer()
    
    class Meta:
        model = Supplier
        fields = ['first_name', 'middle_name', 'supplier_type']
  1. 修改views.py:
from main.models import Supplier
from .serializers import SupplierSerializer
from django.http import JsonResponse

def patientdetails(request):
    supplier_id = request.POST.get('supplier')
    supplier = Supplier.objects.filter(id=supplier_id).select_related('supplier_type').first()
    
    if supplier:
        serializer = SupplierSerializer(supplier)
        data = serializer.data
    else:
        data = {}
    
    return JsonResponse({'data': data})

额外注意点

你的Ajax代码里有个变量名错误:定义的是patient_id,但传给后端的是supplier_id,要改成一致;另外Django的POST请求需要带CSRF Token,否则会被拦截,补充上:

修改Ajax代码:

$('.get_supplier_details').click(function (event) {
  var supplier_id = $('#selected-patient').find(":selected").val(); // 统一变量名
  $.ajax({
    type: "POST",
    url: "{% url 'supplier-details' %}",
    data: {
        supplier: supplier_id
    },
    // 加入CSRF Token
    headers: {
        'X-CSRFToken': $('input[name=csrfmiddlewaretoken]').val()
    }
  }).done(function(data){
    console.log(data);
  });
});

内容的提问来源于stack exchange,提问作者BootCamp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 06:05:07