基本上,我需要根据来自 ManyToManyField 的多个值进行订购。

所以我想要实现的是将具有最多质疑值的对象放在最上面,继续使用具有较少质疑值的对象。继续使用没有任何这些值的对象。

型号:

    class Color(models.Model):
        name = models.CharField(max_length=200)

    class Item(models.Model):
        surface_color = models.ManyToManyField(Color)

基于上述模型创建的实例:
  • 项目 1) surface_color=[1, 2, 3]
  • 项目 2)surface_color=[1, 2]
  • 第 3 项)surface_color=[2]
  • 项目 4)surface_color=[1, 3]


  • 现在我需要订购基于多种颜色:

    假查询:Item.objects.all().order_by(surface_color_id=[1, 3])
    查询应具有以下结果:
  • 第 4 项,因为它有 1 和 3
  • 项目 1,因为它有 1 和 3
  • 第 2 项,因为它有 1 个
  • 第 3 项,因为它没有


  • 这可以通过单个查询集实现吗?或者我是否需要为每个组合发送多个查询?

    我在互联网上发现的唯一内容是关于订购多个 字段 ,这是关于

    任何帮助表示赞赏。

    最佳答案

    这应该给你你想要的:

    list(Item.objects.filter(surface_color__in=[1,3]).distinct().annotate(num_colors=Count('surface_color')).order_by('-num_colors')) + list(Item.objects.exclude(surface_color__in=[1,3]).distinct())
    

    它需要两个查询,但您不需要为每个 Item 单独查询。

    用评论分解相同的逻辑:
    # Make sure you import Count somewhere in the file first
    from django.db.models import Count
    
    # id of Color objects to match
    color_ids_to_match = [1,3]
    
    #-----------------------------------------------------------------------------------------------------------------------
    
    # Item objects with Color objects matching `color_ids_to_match`
    # - The `surface_color` field has **at least one** Color object with a matching id from `color_ids_to_match`
    # - This matches Items #4, #1, #2 from your sample data
    items_with_matching_color = Item.objects.filter(surface_color__in=color_ids_to_match).distinct()
    
    # Adds a select field to the query to track the number of surface_color objects matched
    # - **NOT the total** number of Color objects associated through `surface_color`
    items_with_matching_color = items_with_matching_color.annotate(num_colors=Count('surface_color'))
    
    # Order by that field in descending order
    # - Note that the order is undetermined between Item objects with the same `num_colors` value
    items_with_matching_color = items_with_matching_color.order_by('-num_colors')
    
    #-----------------------------------------------------------------------------------------------------------------------
    
    # Item objects **NOT** associated with any Color objects with a id in `color_ids_to_match`
    # - This matches Item #3 from your sample data
    items_without_matching_color = Item.objects.exclude(surface_color__in=color_ids_to_match).distinct()
    
    # Optional - Sets the num_colors field to 0 for this queryset in case you need this information
    from django.db.models.expressions import RawSQL
    items_without_matching_color = items_without_matching_color.annotate(num_colors=RawSQL('0', ()))
    
    #-----------------------------------------------------------------------------------------------------------------------
    
    # Convert the two querysets to lists and concatenate them
    # - This is necessary because a simple queryset union such as `items_with_matching_color | items_without_matching_color`
    #   does not maintain the order between the two querysets
    ordered_items = list(items_with_matching_color) + list(items_without_matching_color)
    

    使用您的示例数据输出:
    >>> ordered_items
    [<Item: 1: <QuerySet [<Color: 1>, <Color: 2>, <Color: 3>]>>, <Item: 4: <QuerySet [<Color: 1>, <Color: 3>]>>, <Item: 2: <QuerySet [<Color: 1>, <Color: 2>]>>, <Item: 3: <QuerySet [<Color: 2>]>>]
    

    请注意,这里的第 1 项在第 4 项之前。您提到两者之间的顺序无关紧要,因为它们都匹配相同数量的 Color 对象。您可以向 order_by 添加另一个参数,以根据您的需要进一步细化排序。

    获取匹配 Color 对象的数量:
    <Item: 1: <QuerySet [<Color: 1>, <Color: 2>, <Color: 3>]>>
    >>> ordered_items[0].num_colors
    2
    >>> ordered_items[1]
    <Item: 4: <QuerySet [<Color: 1>, <Color: 3>]>>
    >>> ordered_items[1].num_colors
    2
    >>> ordered_items[2]
    <Item: 2: <QuerySet [<Color: 1>, <Color: 2>]>>
    >>> ordered_items[2].num_colors
    1
    >>> ordered_items[3]
    <Item: 3: <QuerySet [<Color: 2>]>>
    >>> ordered_items[3].num_colors
    0
    

    关于django - 如何根据 ManyToManyField 中的多个值订购模型?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37674471/

    10-15 11:02