允许 Django 模型中的字段子集中的一个且仅一个字段
Posted
技术标签:
【中文标题】允许 Django 模型中的字段子集中的一个且仅一个字段【英文标题】:Allow one and only one field from fields subset in Django model 【发布时间】:2018-03-12 03:19:21 【问题描述】:我有一个模型模型。该模型有多个属性,其中三个是:domaintld
、subdomain
、url
- 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】:假设您的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')
并废弃 save
和 clean
方法。现在MyModel
可以与任何模型建立关系,无论是DomainTLD
、Subdomain
还是URL
- content_type
指向模型,object_id
保存对象 ID,content_object
,这不会成为数据库中的一个字段,将用于检索对象。
这是一种更简洁的方法,您可以摆脱那种晦涩难懂的clean
方法。
您可以进一步增强它并将content_type
的选项限制为您希望的选项。这个SO answer 解释了这一点。
【讨论】:
以上是关于允许 Django 模型中的字段子集中的一个且仅一个字段的主要内容,如果未能解决你的问题,请参考以下文章
Flutter-如何一次且仅一次渲染listview.builder中的所有项目
允许 Django 模型 ForeignKey 字段的表单上的 TextInput