How can I implement a Model field with dynamic choices?

I have a model to store differents plans of a service and I need to associate each object of this model with and ID that I get from a RETS service.

So I’ve created an integer field with choices that are loaded wit the response of the api call to get all the valid ids.

def get_active_plans():
response = requests.request("GET", url, headers=headers, data=payload)
active_plans = [
    (p["plan_id"], str(p["plan_id"]) + " - " + p["unique_name"])
    for p in response.json()
]
return active_plans

# Model Field
plan_id = models.IntegerField(choices=get_active_plans(), default=0, unique=True)

The problem is when I’m triying to create an object from the admin this is not showing the list of valid choices updated, because the list of choices in the field of model instance to register the admin isn’t updated.

Anyone knows how to solve it?

You probably need to create a custom form used by your ModelAdmin class. In your form, you can pass the get_active_plans function in to that form field as the choices for that form. (If it’s truly that dynamic, that’s how you would want to do it with all your forms using that field.)

Note - the documentation for choices says that you can pass an iterable or a callable. It will be more dynamic if you pass the callable as the choices instead of the iterable.
e.g. choices=get_active_plans() calls the get_active_plans function which generates the iterable for use by the field. It’s called one time when the model class is created. However, choices=get_active_plans passes the callable - which means that function will be called each time that field is used.

Follow-up note on this - if that field is that dynamic, you could run into problems bringing up a previously entered model and trying to save a change. Applying this type of choice at the model level means that the valid values are those values that are valid at the time the model is being saved, not the time when it was entered. (This may not be an issue for you, but you should be aware of the situation.)

A custom form for the model admin was my first idea and should be enough, but this model is a Translatable model (I’m using django parler) and I started to find problems adding custom fields, so this solution became too complex just to reference an ID.

But thanks to your suggestion I think will be better to create a very simple model with the custom field that loads the valid options. And then create a foreing key to this model from the original one.

What do you think?

Thanks a lot.

If it’s “that complex”, then I’d say you’re probably pushing the Django admin beyond what it’s supposed to do and would be better off creating your own form. The Django admin is not designed or intended to be the primary UI of an application.