Django中的复合外键

时间:2017-02-10 18:00:20

标签: python django postgresql django-models

我需要Django中的复合外键,不支持。我可以手动将其添加到数据库,或通过迁移,但它不会反映在模型定义(sadpanda)中。 后端数据库是postgres。

这是我的模特:

class Trial(models.Model):
    kit = models.ForeignKey(to='Kit')

class Kit(models.Model):
    name = models.CharField(max_length=500)


class Component(models.Model):
    kit = models.ForeignKey(null=True, blank=True, to='Kit', related_name='components')


class ComponentOverride(models.Model):
    trial = models.ForeignKey(to='Trial')
    kit = models.ForeignKey(to='Kit')
    component_to_replace = models.ForeignKey(to='Component', related_name='replaced')
    component_replace_with = models.ForeignKey(to='Component', related_name='replaced_with')

我想在trial_id和kit_id(模型中的试用版和套件)列的ComponentOverride表上对试用表上的id和kit id列进行外键约束(id由django自动创建,模型中的套件是表格中的kit_id。

基本上我想要一个等价物:

ALTER TABLE app_label_trial
    ADD CONSTRAINT app_label_trial_unique_trial_id_kit_id
    UNIQUE (id, kit_id);
ALTER TABLE app_label_componentoverride
    ADD CONSTRAINT app_label_componentoverride_comp_constraint_trial_id_kit_id
    FOREIGN KEY (kit_id, trial_id)
    REFERENCES app_label_trial(id, kit_id)
    DEFERRABLE INITIALLY DEFERRED;

我认为我需要复合键,因为每次试验可以有多个组件覆盖。

试用版有一个套件,它有许多组件。然而,试验可能有一个或多个组件覆盖,这实际上是从一个组件中取出一个组件并用另一个组件替换它。此架构明确地捕获了该替换的信息,这也是我不能一起使用唯一的原因。我想确保componentoverride表中的每个trial_id,kit_id组合都是试用表中的有效组合。

2 个答案:

答案 0 :(得分:1)

我最初在最初的迁移结束时把它放到了这里:

migrations.RunSQL("""
            ALTER TABLE qc_trials_trial
                ADD CONSTRAINT qc_trials_trial_unique_trial_id_kit_id
                UNIQUE (id, kit_id);
            ALTER TABLE qc_trials_componentoverride
                ADD CONSTRAINT qc_trials_componentoverride_comp_constraint_trial_id_kit_id
                FOREIGN KEY (kit_id, trial_id)
                REFERENCES qc_trials_trial(id, kit_id)
                DEFERRABLE INITIALLY DEFERRED
"""),

如果这是我预计要做的事情,我会为它编写一个自定义操作。 https://docs.djangoproject.com/en/1.10/ref/migration-operations/#writing-your-own

答案 1 :(得分:1)

针对上述情况的简单解决方案是从<table border='1px solid black'> <tr id='test'> <td>1</td> <td>1</td> <td>1</td> </tr> <tr id='rtt'> <td>2</td> <td>2</td> <td>2</td> </tr> <tr id='weftest'> <td>3</td> <td>3</td> <td>4</td> </tr> <tr id='vsfvsfv'> <td>4</td> <td>4</td> <td>4</td> </tr> <tr id='yukyktest'> <td>5</td> <td>5</td> <td>5</td> </tr> <tr id='sfsvfsfv'> <td>6</td> <td>6</td> <td>6</td> </tr> </table> <button type='button' onclick='removeRow()'>Remove</button>中省略kit。如果您引用ComponentOverride中的Trial,则可以通过ComponentOverride隐式引用该试用版的工具包。通过在trial__kit_id中另外保存kit_id,就可以不必要地复制数据。通过不两次保存相同的数据,约束问题就自动消失了。

(这是一个古老的问题,但是吸引人的标题仍在引导一些访问量,因此上面的内容可以节省一些人在不需要时无需使用复合外键的麻烦。)