【问题标题】:Ordering on a field in the 'through' Model of recursive ManyToMany relation in Django在 Django 中递归多对多关系的“通过”模型中对字段进行排序
【发布时间】:2009-08-12 12:07:24
【问题描述】:

假设以下模型:

class Category(models.Model):
    related = models.ManyToManyField('self', symmetrical = False, through = 'CategoryRelation', null = True, blank = True)

假设以下中间“通过”关系:

class CategoryRelation(models.Model):
    source = models.ForeignKey('Category', null = False, blank = False, verbose_name = _('source'), related_name = 'relation_source')

    target = models.ForeignKey('Category', null = False, blank = False, verbose_name = _('target'), related_name = 'relation_target')

    order = models.PositiveIntegerField(_('order'), null = False, blank = True, default = 0)

    class Meta:
        ordering = ( 'order', )

如何在保留排序的同时获取与给定类别相关的类别对象?以下代码将生成正确的类别对象,但顺序不正确,即使使用.distinct(),也会在查询集中包含重复条目:

relations = CategoryRelation.objects.filter(source = self)

Category.objects.filter(relation_target__in = relations).order_by('related')

【问题讨论】:

    标签: django recursion many-to-many sql-order-by


    【解决方案1】:

    以下内容可用于正确排序,但不会遗漏重复条目:

    relations = CategoryRelation.objects.filter(source = self)
    
    Category.objects.filter(relation_target__in = relations).order_by('relation_target')
    

    调用 .distinct() 不会有什么不同,因为之后会应用 .order_by() 逻辑。但是,在这种情况下,可以利用 order 是一个正整数字段这一事实,并使用 relation_target 字段的 order 字段的 Min 值注释每个 Category,并使用这个新的注释字段进行排序:

    return Category.objects.filter(relation_target__in = relations).annotate(relation_target_order = models.Min('relation_target__order')).order_by('relation_target_order')
    

    这几乎完成了,但是由于这个查询的语义本质上使它是唯一的,所以调用 .distinct() 只是为了确保 distinct 标志为 True 以便以后可以与其他不同的查询组合是明智的:

    return Category.objects.filter(relation_target__in = relations).annotate(relation_target_order = models.Min('relation_target__order')).order_by('relation_target_order').distinct()
    

    在这种情况下 .distinct() 丝毫不会影响查询,而是确保 db/models/sql/query.py 方法 combine(self, rhs, connector) 通过其断言:

    assert self.distinct == rhs.distinct, \ ...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-12-22
      • 1970-01-01
      • 2011-02-22
      • 2020-07-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-06
      • 1970-01-01
      相关资源
      最近更新 更多