Django 模型 - 至少多对多之一

Posted

技术标签:

【中文标题】Django 模型 - 至少多对多之一【英文标题】:Django models - at least one in many to many 【发布时间】:2012-03-24 12:46:41 【问题描述】:

如何确保至少设置了一个多对多关系?

例如:如果我有一个 listing 模型,它的 image 字段与 images 具有多对多关系。如何确保至少设置了一张图片

额外问题:如果最小值不是一个怎么办?最大值呢?

【问题讨论】:

确保是什么意思?除非有所需数量的图像,否则阻止保存? 是的,确保至少存在一个(如果可能的话,还有一个最大值) 您需要它来过滤列表或其他地方吗?过滤时,您可以使用注释并按结果编号过滤。 根据 [this answer][1] 这是不可能的。 [1]:***.com/questions/10480322/… 【参考方案1】:

您可以实现一个函数来检查Listing 实例是否至少有一个图像实例,并将该函数连接到Listing 模型的pre_save signal

会是这样的,(假设您使用的是 django 1.3)

from django.db.models.signals import pre_save
from django.dispatch import receiver
from myapp.models import Listing
...
@receiver(pre_save, sender=Listing)
def check_image_requirement(sender, instance, **kwargs):
    if instance.images.count() == 0:
        raise your_own_exception("Listing is required to have at least one image")

您需要在哪里实现 your_own_exception

以下补充是对 PO 进一步问题的回应

实现Listing.clean() 是实现相同验证规则的另一种方法。事实上,这是语义上正确的方法,因为Model.clean() 用于自定义模型验证。但是采用这种方法会不太方便 - 要触发clean(),您必须手动调用full_clean()(如果您不使用模型表单),或者手动调用is_valid()(使用模型表单时),对在调用列表实例的save() 之前。 Reference

另一方面,使用pre_save 信号方法,您可以确定无论何时您在实例上调用save(),验证规则始终应用于Listing 实例。

选择一个而不是另一个不是对或错,而只是一个设计决定。这两种方法都可以实现您的需求,并将业务/领域逻辑(即您的验证规则)保留在模型层中。

【讨论】:

我对 phython/django 还是很陌生。 pre_save 是否在字段验证之前运行(例如在确保整数字段为整数或外键约束匹配之前)?为什么 pre_save 而不是 clean()?使用 clean() 时,我是覆盖字段验证还是扩展它?感谢您的帮助! @RS7 - 不用担心。每个人都在这里学习,包括我自己。为了回答您的进一步问题,我已添加到我的答案中。 谢谢,信息量很大——最后一个问题:如果listing 模型有许多由image 模型表示的图像怎么办。如果我正确理解了这些文档,而不是多字段 images,我会创建一个单独的模型,是吗?所以要检查是否满足最低要求,我会以同样的方式访问它吗? self.image.count() 如果我在 clean() 做? @RS7 - 视情况而定。如果您只需要一个简单的多对多关系(即无需记录有关关联的其他属性),那么您只需要一个ManyToManyField。假设您决定在关联上设置到期日期(即附加属性),那么您将需要一个ManyToManyField,以及一个表示关联/关系的附加模型。我强烈推荐你去this section。第一段基本上重申了我刚才解释的内容。 @RS7 - 是的,self.image.count() 仍然适用于 clean()

以上是关于Django 模型 - 至少多对多之一的主要内容,如果未能解决你的问题,请参考以下文章

laravel 模型关联之(多对多)

Django自引用多对多模型

Django:按多对多字段订购模型

如何在双连接关系之后在 Django 中执行查询(或:如何绕过 Django 对多对多“通过”模型的限制?)

Django模型(继承、一对多、多对多)

Django ORM - 通过模型查询多对多?