繁体   English   中英

Django:外键是可选的,但唯一?

[英]Django: Foreign key optional but unique?

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

bc应该一起唯一, 包括NULL

因此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 |
+----+------+------+

前2行只能由django插入一次。 太好了 :)

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

UPDATE

我发现可以完成工作的东西,但看起来确实很hack ..有什么想法吗?

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

也许有更好的解决方案,但是您可以执行以下操作:

  1. 创建一个新的属性d并找到一种组合b_idc_id的通用方法(例如str(b_id) + "*" + str(c_id) ,并在模型创建时自动执行(信号机制可能会派上用场)
  2. 使用d作为primary_key

这是更多的解决方案,而不是解决方案,但是应该可以解决问题。

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

这不是Django的问题,而是SQL规范本身的问题-NULL不是值,因此唯一性约束检查不得将其考虑在内。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM