Django:外键可选但独一无二?

时间:2013-10-29 10:11:34

标签: python sql django

我的模型(A)有2个外键:bc

bc应该是唯一的包含空

因此bc一起只能为NULL ONCE

但是,我无法在Django中完成此任务。这是我到目前为止的代码。任何帮助表示赞赏!

-_-

class A(models.Model):
  b = models.ForeignKey('B', blank = True, null = True)
  c = models.ForeignKey('C', blank = True, null = True)

  class Meta:
    unique_together = (
      ('b', 'c')
    )

此代码将在数据库中生成此不需要的结果:

+----+------+------+
| id | b_id | c_id |
+----+------+------+
|  1 |    2 | 3    |
|  2 |    2 | 77   |
|  3 |    2 | NULL |
|  4 |    2 | NULL |
|  5 | NULL | NULL |
|  6 | NULL | NULL |
+----+------+------+

前两行只能由django插入一次。 很棒:)

但是,剩余的行对我来说是重复的条目,我想限制它。

更新

我找到了可以完成工作的东西,但它看起来真的很糟糕...... 有什么想法吗?

class A(models.Model):
  def clean(self):
    from django.core.exceptions import ValidationError

    if not any([self.b, self.c]):
      if Setting.objects.filter(b__isnull = True, c__isnull = True).exists():
        raise ValidationError("Already exists")

    elif self.b and not self.c:
      if Setting.objects.filter(c__isnull = True, b = self.b).exists():
        raise ValidationError("Already exists")

    elif self.c and not self.user:
      if Setting.objects.filter(c = self.c, b__isnull = True).exists():
        raise ValidationError("Already exists")

3 个答案:

答案 0 :(得分:1)

也许有更好的解决方案,但你可以做到以下几点:

  1. 创建新属性d并找到合并b_idc_id的通用方法(例如str(b_id) + "*" + str(c_id),并在模型创建时自动执行此操作(信号机制可能会出现)方便,在这里)
  2. 使用d作为primary_key
  3. 这更像是一个解决方案,但它应该可以解决问题。

    还有一个想法:在创建/更新实例时,是否可以检查是否存在“Null”/“Null”的现有实例?这不会解决您在数据库级别上的问题,但逻辑将按预期工作。

答案 1 :(得分:1)

这不是Django的问题,但是对于SQL规范本身 - NULL不是值,因此不能将其考虑在唯一性约束检查中。

你可以在你的数据库中有一个“伪空”B记录和一个“伪空”C记录,并使它们成为默认值(当然不允许NULL),或者像OBu建议的那样具有非规范化字段。

答案 2 :(得分:-1)

您可以对 b_id 列使用唯一约束。它不允许重复条目。即使对于a_id列,也可以使用主键。主键表示唯一键和非空约束的组合。