如何限制 Django ORM 中外键关系的数量?

Posted

技术标签:

【中文标题】如何限制 Django ORM 中外键关系的数量?【英文标题】:How to limit nubmer of Foreign key relations in Django ORM? 【发布时间】:2020-10-22 15:54:27 【问题描述】:

我有一个与自身递归相关的模型。其内容如下。

class Category(models.Model):
    name = models.CharField(max_length=200)
    parent = models.ForeignKey(
        'self', blank=True, null=True,
        related_name='children', on_delete=models.CASCADE)

    class Meta:
        verbose_name_plural = "Categories"

    def __str__(self):
        path = [self.name, ]
        node = self.parent
        while node is not None:
            path.append(node.name)
            node = node.parent
        return '->'.join(path[::-1])

我想要实现的是一个小验证,防止超过 3 个孩子进入父类别。 例如,如果我按照上面的状态创建,它将保存如下:

Programming->Back-end->Python->ifelse.

我的问题:如何防止父类别有超过 3 个孩子?

【问题讨论】:

我很困惑:您是在问不能在上面创建类别“ifelse”,还是说类别“Python”不能有超过 3 个子项(“ifelse”,“ for", "while", 但不是 "trycatch")? 【参考方案1】:

你可以试试model validation

from django.core.exceptions import ValidationError


class Category(models.Model):
    name = models.CharField(max_length=200)
    parent = models.ForeignKey(
        'self', blank=True, null=True,
        related_name='children', on_delete=models.CASCADE)

    def clean(self):
        if self.parent:
            if self.get_parents_length(self) > 3:
                raise ValidationError("Parent has already got 3 children!")

    class Meta:
        verbose_name_plural = "Categories"

    def __str__(self):
        path = [self.name, ]
        node = self.parent
        while node is not None:
            path.append(node.name)
            node = node.parent
        return '->'.join(path[::-1])

    @staticmethod
    def get_parents_length(cat):
        parents = [cat.name]
        node = cat.parent
        while node is not None:
            parents.append(node.name)
            node = node.parent
        return len(parents)

【讨论】:

只要把它放在 save() 中。不要在 save 中调用full_clean:最好的情况是它会被调用两次,最坏的情况是它会在不需要的地方进行模型验证(例如在信号中)。 @Melvyn,我能想到的最好的客户端是在视图中,就像文档所说的那样,你能帮忙解释一下,为什么如果把 full_clean 放在 save 里面会被调用两次 @minglyu 我已经检查过它并没有真正起作用,但我明白了,谢谢,我将对您的答案进行一些小改动并接受它。谢谢 @Madiyor 我认为你最好使用像django-mptt 这样的第三方库来实现Category,它为tree 之类的对象实现了复杂的数据结构,这样的递归非常低效 在这种情况下,我认为你不会有单个对象检索/创建的问题,但你可能会遇到复杂过滤的问题,这会导致单个操作中的许多查询,mptt 使用nested set 和其他一些数据结构来实现关系数据库中的树。因此您可以在单个查询中完成大部分任务,值得一看 imo。

以上是关于如何限制 Django ORM 中外键关系的数量?的主要内容,如果未能解决你的问题,请参考以下文章

SQLAlchemy(三):外键连表关系

Django orm关系表的创建 路由层以及视图层

Flask-如何理解创建数据模型中外键关联

如何在Django中查询具有特定数量的外键关系并且在这些外键值中具有特定值的对象?

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

如何在课堂上设置两个外键? DJANGO ORM