如何将外键选择限制在同一模型中的另一个外键

时间:2013-06-28 07:48:23

标签: python django database-design django-models

我正在制作django应用程序而我正面临一个问题。我正在尝试定义一个模型,其中一个ForeignKey将取决于另一个ForeignKey

描述部分

我的申请是关于做出选择。

因此,假设您有decisiondecision有多个choice,而choicestatus(因为其他约束)。

status可用于多个choices,但status只能与一个decision相关,choice,____________, ,____________, | | 1, n 1, 1 | | | Decision |------------------| Status | |____________| |____________| | | | 1, n | 1, n | | | 1, 1 | ,_____|______, | | | 1, 1 | | Choice |-------------------------' |____________| 相同到。

数据库架构

它不是固定的,如果需要可能会更改:

class Decision (models.Model):
    name = models.CharField (max_length = 63)

class Status (models.Model):
    value = models.CharField (max_length = 63)
    decision = models.ForeignKey (Decision)

class Choice (models.Model):
    name = models.CharField (max_length = 63)

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

代码

这是我当前的(简化的)( not working )代码:

limit_choices_to = {'decision' : decision}

这里的重要部分是{{1}}。

额外信息

我发现另一个SO问题(In django, how to limit choices of a foreignfield based on another field in the same model?)处理同一个问题,但问题是变老,最好的答案是依赖外部应用程序(django-smart-selects)。

我宁愿不必使用外部的东西,我也不明白为什么只使用Django就无法解决像3表关系这样简单的东西!

如果有人有任何解决方案或任何建议,请告诉我。

4 个答案:

答案 0 :(得分:3)

你所要求的是不可能的,至少不在你设定的范围内(没有形式,没有外部库)。 status模型的Choice字段是外键,两个表之间的关系...它不处理过滤本身,简单地说 - 它没有此功能。这不是 django 的事情,这是数据库的事情。 Django ORM并不像您想象的那样远离数据库,它很精彩,但它并不神奇。

一些可用的解决方案是:

  • 通过过滤查询集
  • 在FormField级别执行此操作
  • 使用类似 django-smart-selects 的内容(以上内容)
  • 覆盖模型上的save,在那里添加检查,如果失败则抛出错误
  • 设置status属性,并在设置
  • 时对其进行验证检查

如果您使用FormField方法以及覆盖save,您将获益于知道Choice无法保存,但它违反了此限制用户的结尾(填写表单)或后端(在.save()实例上调用Choice的代码。

答案 1 :(得分:1)

我不熟悉Django,但是如果你试图解决“同一个选择与问题相关的部分问题”,那就是如何在数据库级别完成它:

enter image description here

请注意识别关系的用法,因此DecisionId将在“分支”下向下迁移,并在“底部”合并。因此,如果ChoiceStatus,则它们都必须链接到同一Decision

答案 2 :(得分:1)

我认为你需要的是through模型,如下所示:

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")    

这样,每个决策都有很多选择,每个选择只有一个状态。您可以执行以下查询: my_decision.choices.all()my_status.decision_set.all()

我建议您查看documentation以获取有关如何使用模型的示例

答案 3 :(得分:0)

在以下语句中,decision既不是可调用对象,也不是models.Q对象:

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

这是一种表示数据的方法:

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)

这是另一个:

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)