允许Django模型中的字段子集中只有一个字段

时间:2017-09-30 10:54:40

标签: django postgresql django-models model

我有一个模型模型。此模型具有多个属性,其中三个属于:domaintldsubdomainurl - OneToOneField s。

我试图让这些字段中只有一个非空。

我的方法有效,但我很好奇是否有更好的方法(我使用 PostgreSQL )。

def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
    self.clean()
    super(Model, self).save(force_insert, force_update, using, update_fields)

def clean(self):
    super(Model, self).clean()

    if not(((bool(self.url) ^ bool(self.domaintld)) ^ bool(self.subdomain)) and not(self.url and self.domaintld and self.subdomain)):
        raise exceptions.ValidationError("One and only one field can be used: url,domaintld,subdomain")

1 个答案:

答案 0 :(得分:0)

假设您的models.py

中有类似内容
class DomainTLD(models.Model):
    # attributes and methods

class Subdomain(models.Model):
    # attributes and methods

class URL(models.Model):
    # attributes and methods

class MyModel(models.Model):
    domaintld = models.OneToOneField(DomainTLD)
    subdomain = models.OneToOneField(Subdomain)
    url = models.OneToOneField(URL)
    # other attributes and methods

我建议使用django contenttypes并重构如下:

class MyModel(models.Model):
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

并废弃了saveclean方法。现在MyModel可以与任何模型建立关系,无论是DomainTLDSubdomain还是URL - content_type指向模型,object_id成立对象ID和content_object将不会成为数据库中的字段,将用于检索对象。

这是更清洁的方式,你可以摆脱那种模糊的clean方法。 您可以进一步增强它,并将content_type的选项仅限于您希望的人。这个SO answer解释了这一点。