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'即可显示计算结果。
额外注意事项
- 你的
golf_field_playing字段设置了default='for_nothoing',需确保数据库中存在golf_club_name为'for_nothoing'的GField实例,否则会触发关联不存在的错误; - 建议给
R1-R5字段设置default=0,避免实例创建时出现空值问题; - 所有计算逻辑中加入异常判断,避免因数据缺失导致页面崩溃。
内容的提问来源于stack exchange,提问作者Vasyokvk
相关产品推荐
相关产品推荐

