Django modelform_factory生成的表单提交时报选项无效错误如何解决
问题根源
ganador是关联Jugador表的外键字段,你在模型层写死的choices值是固定字符串Jugador A/Jugador B,但外键字段校验需要接收Jugador表的主键ID值,类型不匹配直接触发校验失败。- 每个对局的参赛者都不一样,你全局生成的表单没有动态适配当前对局的两个玩家作为可选选项。
- 提交表单时没有指定要更新的对局ID,表单保存时会直接新建对局而不是修改已有对局的胜者。
- 模板中所有对局共用同一个表单实例,无法对应各自的参赛者选项。
修改步骤
1. 修正models.py的字段配置
删除ganador字段写死的choices,因为每个对局的可选胜者是动态变化的,不能在模型层固定配置:
class Juego(models.Model): torneo = models.ForeignKey(Torneo, on_delete=models.CASCADE, null=False) ronda = models.ForeignKey(Ronda, on_delete=models.CASCADE, null=False) jugadorA = models.ForeignKey(Jugador, on_delete=models.SET_NULL, null=True, related_name='jugadorA') jugadorB = models.ForeignKey(Jugador, on_delete=models.SET_NULL, null=True, related_name='jugadorB') puntuacionA = models.IntegerField(default=0) puntuacionB = models.IntegerField(default=0) # 删掉固定choices配置 ganador = models.ForeignKey(Jugador, on_delete=models.SET_NULL, null=True, default=None)
2. 自定义动态表单类
替换原来的modelform_factory生成的静态表单,动态适配每个对局的参赛者作为可选胜者:
from django import forms from .models import Juego class GanadorForm(forms.ModelForm): class Meta: model = Juego fields = ['ganador'] def __init__(self, *args, **kwargs): # 接收当前对局实例 juego = kwargs.pop('juego', None) super().__init__(*args, **kwargs) if juego: # 动态设置可选选项为当前对局的两名玩家,值为玩家主键,显示名为玩家姓名 self.fields['ganador'].choices = [ (juego.jugadorA.id, f"{juego.jugadorA.nombre} {juego.jugadorA.apellido}"), (juego.jugadorB.id, f"{juego.jugadorB.nombre} {juego.jugadorB.apellido}") ]
3. 调整视图逻辑
修正表单绑定、更新逻辑,给每个对局生成单独的表单实例:
def detalleTorneo(request, id): torneo = Torneo.objects.get(pk=id) jugadoresPares = False jugadores = torneo.jugadores.all() no_jugadores = jugadores.count() rondas = Ronda.objects.filter(torneo=torneo) juegos = Juego.objects.filter(torneo=torneo) if request.method == 'POST': # 从请求中获取要更新的对局ID juego_id = request.POST.get('juego_id') juego = Juego.objects.get(pk=juego_id) # 绑定表单时传入对局实例、提交数据、要更新的对局对象 formaGanador = GanadorForm(request.POST, juego=juego, instance=juego) if formaGanador.is_valid(): formaGanador.save() # 给每个对局绑定对应的表单实例 for juego in juegos: juego.forma = GanadorForm(juego=juego, instance=juego) if (no_jugadores % 2) == 0: jugadoresPares = True return render(request, 'torneos/detalle.html', { 'juegos': juegos, 'torneo': torneo, 'no_jugadores': no_jugadores, 'jugadoresPares': jugadoresPares, 'rondas': rondas })
4. 修改模板渲染逻辑
每个对局使用对应表单,添加隐藏字段传递对局ID:
{% for ronda in rondas %} <h3>Ronda {{ronda.numero}}</h3> <ul> {% for juego in juegos %} {% if juego.ronda == ronda %} <li> <form method="post"> {% csrf_token %} <!-- 隐藏字段传递当前对局ID --> <input type="hidden" name="juego_id" value="{{juego.id}}"> <strong>{{juego.jugadorA.nombre}} {{juego.jugadorA.apellido}} vs {{juego.jugadorB.nombre}} {{juego.jugadorB.apellido}}</strong> | {{juego.forma}} <button type="submit">Ingresar Resultados</button> <br> </form> </li> {% endif %} {% endfor %} </ul> {% endfor %}
内容的提问来源于stack exchange,提问作者Carlos GM
相关产品推荐
相关产品推荐

