Admin ChoiceField not updating

I’m not sure if this is the same issue as this:

But I’ll give it a shot anyway.

I have this models.py

from django.db import models
from django.core.validators import MinLengthValidator, RegexValidator


class Player(models.Model):
    name = models.CharField(
        unique=True,
        max_length=64
    )
    birth_year = models.CharField(
        max_length=4,
        default=1900,
        validators=[
            MinLengthValidator(4),
            RegexValidator(
                r'^[12][0-9]{3}$',
                message='Year must be a 4-digit number.'
            )
        ],
        verbose_name='Born Year'
    )

    def __str__(self):
        return self.name


class Tournament(models.Model):
    name = models.CharField(
        max_length=32,
        unique=True
    )
    year = models.CharField(
        max_length=4,
        default=1900,
        validators=[
            MinLengthValidator(4),
            RegexValidator(
                r'^[12][0-9]{3}$',
                message='Year must be a 4-digit number.'
            )
        ]
    )
    winner = models.CharField(
        max_length=64
    )

    def __str__(self):
        return self.name

And I have custom admin_forms.py:

from django import forms
from .models import Player, Tournament


class TournamentForm(forms.ModelForm):
    class Meta:
        model = Tournament
        fields = '__all__'

    player_choices = [('', '')]
    queryset = Player.objects.all().order_by('name')
    for name in queryset:
        player_choices.append((name, name))

    winner = forms.ChoiceField(choices=player_choices)

In the admin panel, if I add a new player in the Players table and then go to the Tournament table, the winner ChoiceField won’t show the new player. The new player does show up fine in the Players table however.
I have to stop “runserver” and restart “runserver” and then, the new player will show up in the ChoiceField. While it’s fine for me in a dev environment, I don’t see this working too well in production =P

Using Django 4.1 with sqlite3.

Not sure why the field won’t update :frowning:

EDIT: I get the same result if I use a ForeignKey instead of a CharField for the ‘winner’ variable in models.py

Yes, that is one of the threads in the forum covering this general topic.

Also see How to pass iterable list of filtered users in Django template using form? and Populate choice field from model with conditional query Django

Additionally, there’s another factor in play here.

You have your code at the class level and not within a function. Class-level code is executed once, when the class is loaded. It is not executed every time an instance of that class is created. All procedural code that you want to execute at the “instance” layer needs to be in a function.

Finally, instead of:

I would suggest:
player_choices = ('', '') + Player.objects.all().order_by('name').values_list('name', 'name')

Additionally, be aware of the section in the docs about the “default” entry in the Choices docs.

Thanks a lot Ken. That was very valuable information!

Made a get_players() function outside the class as suggested, moved the queryset inside it to return the list of tuples and then used this function as the callable:

winner = forms.ChoiceField(choices=get_players)

Now the choices update successfully on admin page load :+1:

For clarity, I did not suggest that get_players should (or need) be outside the class. It would be appropriate for that function to reside within the class as well.

Yes, you did explain why.
To be honest, I had already tried it, but I was using get_players() with the parentheses instead of without for the callable, that’s why it never worked for me.

But yes, in most circumstances, I’d leave the function inside the class.
Thanks a lot for you help :wink: