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属性访问错误。
修复步骤
修改
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)优化查询性能(可选)
为避免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
相关产品推荐
相关产品推荐

