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

Django Admin显示外键ref_code报错:'NoneType'对象无该属性

问题描述

在Django Admin的Cliente管理列表中尝试显示关联Orden模型的ref_code字段时,触发错误:'NoneType' object has no attribute 'ref_code'。当仅返回obj.orden时能正常显示关联对象名称,但访问ref_code字段就报错。

相关代码

models.py

class Orden(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL,
                             on_delete=models.CASCADE)
    producto = models.ManyToManyField(
        ProductosOrden)
    medio_de_venta = models.ForeignKey(MediosVenta, null=True, blank=False, on_delete=models.SET_NULL)
    fecha_venta = models.DateField(blank=False, null=False)
    ordenado = models.BooleanField(default=False)
    ref_code = models.CharField(max_length=20, blank=True, null=True)
    promo = models.ForeignKey(Promos,null=True, blank=True, on_delete=CASCADE )
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    vendido_por = models.CharField(max_length=20, null=False, blank=False)

    class Meta:
        verbose_name_plural = "Ordenes"
        ordering = ["-id"]

    def __str__(self):
        return self.user.username

class Cliente(models.Model):
    nombre = models.CharField(max_length=60, null=False, blank=False)
    email = models.EmailField(blank=False, null=False)
    email_valido = models.BooleanField(null=True, blank= True, verbose_name='Email Válido')
    telefono = models.CharField(
        max_length=17, null=True, blank=True, verbose_name='Teléfono')
    lead = models.ForeignKey(Leads, models.SET_NULL,  null=True, blank=True)
    activo = models.BooleanField(default=False)
    orden = models.ForeignKey(Orden, null=True, blank=True,  on_delete=CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    created_by = models.CharField(max_length=20, null=False, blank=False)

    class Meta:
        verbose_name_plural = "Clientes"
        ordering = ["-id"]

    def __str__(self):
        return self.nombre

admin.py

class ClienteAdmin(admin.ModelAdmin):
    list_display = ('id', 'nombre', 'activo', 'get_ref_code')
    readonly_fields=('id',)
    search_fields = ['nombre']
    actions = ['activa','desactivar']

    @admin.action(description='Desactivar')
    def desactivar(self, request, queryset):
        queryset.update(activo = False)

    @admin.action(description='Activar')
    def desactivar(self, request, queryset):
        queryset.update(activo = True)

    @admin.display(description= 'ref_code')
    def get_ref_code(self, obj):
        if not obj.orden.ref_code:
            return None
        else: 
            return obj.orden.ref_code

解决方法

错误原因

Cliente模型的orden字段设置了null=True, blank=True,意味着存在没有关联Orden的Cliente记录。此时obj.orden的值为None,直接访问obj.orden.ref_code就会触发NoneType属性访问错误。

修复步骤

  1. 修改get_ref_code方法,先判断关联对象是否存在
    将admin.py中的get_ref_code方法修改为:

    @admin.display(description='ref_code')
    def get_ref_code(self, obj):
        # 先检查orden是否存在,再访问ref_code
        if obj.orden:
            return obj.orden.ref_code or None
        return None
    

    或者使用更简洁的getattr短路写法:

    @admin.display(description='ref_code')
    def get_ref_code(self, obj):
        return getattr(obj.orden, 'ref_code', None)
    
  2. 优化查询性能(可选)
    为避免Django Admin在渲染列表时产生N+1查询(每条Cliente单独查询一次Orden),可以在ClienteAdmin中添加list_select_related配置:

    class ClienteAdmin(admin.ModelAdmin):
        list_display = ('id', 'nombre', 'activo', 'get_ref_code')
        readonly_fields=('id',)
        search_fields = ['nombre']
        actions = ['activa','desactivar']
        # 添加此行,预加载关联的Orden数据
        list_select_related = ['orden']
        
        # 其他方法保持不变...
    

内容的提问来源于stack exchange,提问作者Jorge López

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 11:15:30