Reputation: 1684
Let us consider the following model
class MyModel(models.Model):
stock = models.IntegerField(blank=True, default=0)
to_be_filled_later = models.CharField(max_length=20, blank=True)
suppose also that I manually created an entry with stock
set to 42 and to_be_filled_later
left blank.
When I go to the admin panel (modification) of MyModel
and select my new entry, I would like to set to_be_filled_later
to some value, but I also want to restrict the set of possible values based on the current value of self.stock
, i.e. 42.
Since Field.choices
can be set to any iterable, one would be tempted to do something like
class MyModel(models.Model):
stock = models.IntegerField(blank=True, default=0)
def restricted_choices(self):
# do something based on self.stock
yield (some_stuff.pk, some_stuff.name)
to_be_filled_later = models.CharField(max_length=20,
blank=True,
choices=restricted_choices(self))
however this won't work because restricted_choices
should be called with a reference to self
that is not defined in the scope where we create the fields (here in the definition of to_be_filled_later
, to be precise).
We could maybe override __init__
but that's not what we want since it would take effect just after every entry creation. What we want is to have a dynamically, instance based choices
.
How would you go with this?
Upvotes: 0
Views: 483
Reputation: 599876
You do want to override __init__
, but in the form, not in the model.
class MyModelForm(forms.ModelForm):
to_be_filled_later = forms.ChoiceField(choices=[])
class Meta:
model = MyModel
def __init__(self, *args, **kwargs):
super(MyModelForm, self).__init__(*args, **kwargs)
if self.instance:
self.fields['to_be_filled_later'].choices = restricted_choices(self.instance.stock)
and assign this form to the model admin for MyModel:
class MyModelAdmin(admin.ModelAdmin):
model = MyModel
form = MyModelForm
admin.site.register(MyModel, MyModelAdmin)
Upvotes: 2