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

Django中OneToOneField取数及Admin list_display展示to_par问题求助

问题分析与解决方案

初始错误原因

你最初在PlayerInstance类里直接编写计算逻辑的方式完全错误:这些代码处于类级别,此时golf_field_playing是Django的OneToOneField字段对象,而非当前实例关联的GField数据对象,自然没有golf_field_par属性;同时R1等也是字段定义对象,不是实例的具体数值,因此触发AttributeError。

你后来将计算逻辑改为实例方法的方向是对的,但admin列表显示的问题需要针对性解决,以下是两种可行方案:


方案一:用@property包装为实例属性

修改PlayerInstance模型,将计算逻辑转为名为to_par的属性,这样admin可直接识别:

class PlayerInstance(models.Model):
    # 保留原有字段定义
    golf_field_playing = models.OneToOneField(GField, default='for_nothoing', on_delete=models.RESTRICT, help_text='where is it taking part?')
    now_at_hole = models.IntegerField()
    today = models.IntegerField()
    R1 = models.IntegerField()
    R2 = models.IntegerField()
    R3 = models.IntegerField()
    R4 = models.IntegerField()
    R5 = models.IntegerField()

    @property
    def to_par(self):
        # 过滤出非0的有效回合
        valid_rounds = [self.R1, self.R2, self.R3, self.R4, self.R5]
        valid_rounds = [score for score in valid_rounds if score != 0]
        counter = len(valid_rounds)
        
        # 处理无有效回合的情况
        if counter == 0:
            return "N/A"
        
        # 处理关联场地不存在的异常
        try:
            par_value = self.golf_field_playing.golf_field_par
        except GField.DoesNotExist:
            return "无场地数据"
        
        total = sum(valid_rounds)
        par_total = par_value * counter
        
        if total >= par_total:
            return f'+{total - par_total}'
        else:
            return f'-{par_total - total}'

之后在admin.py的list_display中直接添加'to_par'即可正常显示。


方案二:在admin中自定义显示函数

如果不想修改模型,可在admin层编写自定义函数调用模型的计算方法:
首先确保模型中的方法仅返回计算结果(无需给self.to_par赋值):

class PlayerInstance(models.Model):
    # 原有字段定义不变
    def calculate_to_par(self):
        valid_rounds = [self.R1, self.R2, self.R3, self.R4, self.R5]
        valid_rounds = [score for score in valid_rounds if score != 0]
        counter = len(valid_rounds)
        
        if counter == 0:
            return "N/A"
        
        if not self.golf_field_playing:
            return "无场地数据"
        
        par_value = self.golf_field_playing.golf_field_par
        total = sum(valid_rounds)
        par_total = par_value * counter
        
        if total >= par_total:
            return f'+{total - par_total}'
        else:
            return f'-{par_total - total}'

然后在admin.py中配置:

from django.contrib import admin
from .models import PlayerInstance

class PlayerInstanceAdmin(admin.ModelAdmin):
    # 替换为你需要显示的其他字段
    list_display = ('now_at_hole', 'today', 'get_to_par')

    def get_to_par(self, obj):
        return obj.calculate_to_par()
    # 自定义admin列表中的列名
    get_to_par.short_description = 'To Par'

admin.site.register(PlayerInstance, PlayerInstanceAdmin)

此时在list_display中添加'get_to_par'即可显示计算结果。


额外注意事项

  1. 你的golf_field_playing字段设置了default='for_nothoing',需确保数据库中存在golf_club_name为'for_nothoing'的GField实例,否则会触发关联不存在的错误;
  2. 建议给R1-R5字段设置default=0,避免实例创建时出现空值问题;
  3. 所有计算逻辑中加入异常判断,避免因数据缺失导致页面崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 02:35:11