Reputation: 1101
I'm trying to limit the choices for a foreign key in my django admin tool. I stumbled across the limit_choices_to
option for the ForeignKey
model: https://docs.djangoproject.com/en/3.2/ref/models/fields/#django.db.models.ForeignKey.limit_choices_to
In my models, I have a Question_logic
that has an attribute ifLogic
which is a foreign key of the model Options
(which represent the possible answers of options of a question).
# Models.py
class Options(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
option = models.CharField(max_length=200)
class Question_logic(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
# error here:
ifLogic = models.ForeignKey(Options, on_delete=models.CASCADE, limit_choices_to=Options.objects.filter(question=question))
thenLogic = models.CharField(max_length=200)
However this approach does not work because apparently you can't reference an object in the model definition itself and I'm getting this error:
django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet.
My logic is quite straightforward: I want the admin to chose only between the options that are relevant for the specific question. How do I implement this correctly?
Thanks.
Upvotes: 1
Views: 2393
Reputation: 5644
Foreign key choices in the admin can be limited via ModelAdmin.formfield_for_foreignkey(). During form instantiation, the current object (i.e. QuestionLogic
) is stored on the request object that is available in the formfield_for_foreignkey()
method.
Note that the object is not stored on the ModelAdmin object because that is not thread-safe.
class QuestionLogicAdmin(admin.ModelAdmin):
def get_form(self, request, obj=None, **kwargs)
# Store Question object on request for later retrieval.
request._obj_ = obj
return super().get_form(request, question, **kwargs)
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "ifLogic" and request._obj_:
question = request._obj_.question
kwargs["queryset"] = Options.objects.filter(question=question)
PS: In Python, it is good practice to use CapitalizedWords naming convention for class names (i.e. QuestionLogic instead of Question_logic). Instance variables should be lowercase with words separated by underscores as necessary to improve readability (i.e. if_logic
instead of ifLogic
). You can read up on that in the PEP8 styleguide.
Upvotes: 1