[Django]-How to restrict Foreign Key choices to another Foreign Key in the same model

1👍

âś…

I’m not familiar with Django, but I if you are trying to solve the “same one the choice is linked to” part of the problem, this is how it can be done at the database level:

enter image description here

Note the usage of identifying relationships, so the DecisionId is migrated down both “branches” and merged at the “bottom”. So if a Choice has Status, they both must be linked to the same Decision.

3👍

What you’re asking is not possible, at least not within the boundaries you’ve set (no forms, no external libraries). The status field of your Choice model is a Foreign Key, a relationship between two tables… it doesn’t deal with filtering itself, simply put – it doesn’t have this feature. And this isn’t a django thing, this is a database thing. The Django ORM isn’t as far away from the database as you probably think, it’s brilliant but it’s not magic.

Some of the available solutions are:

  • Do it at the FormField level by filtering the queryset
  • Use something like django-smart-selects (this does the above)
  • Override save on your model, add the check there and throw an error if it fails
  • Make status a property and do validation checks on it when it’s set

If you go with FormField method as well as overriding save you’ll have the benefit of knowing there’s no way a Choice can be saved it it violates this constraint, from either the user’s end (filling out a form) or the back end (code that calls .save() on a Choice instance.

👤Matt

1👍

I think that what you need here is a through model, like so:

class Choice (models.Model):
    name = models.CharField (max_length = 63)
    status = models.ForeignKey(Status)
    decision = models.ForeignKey(Decision)

class Status(Models.Model):
    name = models.CharField(max_length=20)

class Decision(models.Model):
    name = models.CharField(max_length = 63)
    choices = models.ManyToManyField(Status, through = "Choice")    

This way, every decision has many choices, each of which has only one status. You could do a query like:
my_decision.choices.all() or my_status.decision_set.all()

I suggest you take a look at the documentation for an example on how to use through models

👤Basti

0👍

In the following statement decision is neither a callable nor a models.Q object:

status = models.ForeignKey (Status, limit_choices_to = {'decision' : decision})

here is a way to represent your data:

class Decision(models.Model):
    ...

# a status is relevant for only one decision
# there may be more than one Status per Decision.
class Status(Models.Model):
    decision = models.ForeignKey(Decision)

# each choice is linked to one decision and has a status.
class Choice (models.Model):
    status = models.ForeignKey(Status)
    # if status is mandatory, then you can get the decision
    # from status.decision. per se, this fk could be optional.
    decision = models.ForeignKey(Decision)

here is another one:

class Decision(models.Model):
    ...

# a decision has multiple choices
# a choice pertains to only one decision
class Choice (models.Model):
    decision = models.ForeignKey(Decision)

# each status is relevant to one decision
# and may encompass multiple choices.
class Status(Models.Model):
    decision = models.ForeignKey(Decision)
    # problem with this representation is that this allows for
    # a choice to be linked to multiple statuses.
    # this happens when using M2M instead of ForeignKey.
    choices = models.ManyToManyField(Choice)
👤dnozay

Leave a comment