Django SortedManyToManyField反向关联无法保存排序问题咨询
问题1解答
是的,只有定义SortedManyToManyField的正向关联默认会自带排序维护能力,反向关联的related_name默认使用Django原生的普通多对多管理器,不会处理排序逻辑。
原因是SortedManyToManyField的排序值存储在自动生成的中间表中,排序规则的视角完全从正向模型出发:比如你在Product上定义的categories字段,中间表存储的是每个Product下关联的不同Category的排序优先级,这个排序值本身就不是为「每个Category下关联的Product排序」场景设计的,所以反向管理器默认不会带排序逻辑。
问题2解答
不需要,也不能这么做。如果你在Category中也定义一个指向Product的SortedManyToManyField,会生成两个完全独立的中间表、两个完全无关的多对多关联,和你现在用到的反向关联product_items没有任何关系,也不能解决当前遇到的问题。
可选解决方案
如果确实需要从Category侧操作关联时也维护排序,分两种场景处理:
场景1:你需要的是每个Category下的Product有独立的排序规则:
单独在Category中定义新的SortedManyToManyField即可,注意设置独立的related_name,不要和原有字段冲突:class Category(models.Model): # 原有字段不变 sorted_products = SortedManyToManyField(to=Product, blank=True, related_name="sorted_categories")这是独立的第二组多对多关联,和现有
categories字段互不干扰,各自维护自己的排序。场景2:你只是希望反向查询的时候能沿用正向关联的排序规则,或者反向添加的时候也能正确写入正向的排序值:
可以显式声明中间表,自定义反向管理器,或者操作时手动指定排序值即可,示例如下:- 先显式定义中间表:
class ProductCategoryRelation(models.Model): product = models.ForeignKey(Product, on_delete=models.CASCADE) category = models.ForeignKey(Category, on_delete=models.CASCADE) sort_value = models.IntegerField(default=0) class Meta: ordering = ('sort_value',) # 改造Product的字段 class Product(models.Model): # 原有字段不变 categories = SortedManyToManyField( to=Category, blank=True, related_name="product_items", through=ProductCategoryRelation, through_fields=('product', 'category'), sort_value_field_name='sort_value' )- 反向添加关联的时候手动传入排序值:
# 给c1添加p1、p2、p3,指定排序值 ProductCategoryRelation.objects.create(category=c1, product=p1, sort_value=0) ProductCategoryRelation.objects.create(category=c1, product=p2, sort_value=1) ProductCategoryRelation.objects.create(category=c1, product=p3, sort_value=2)- 反向查询的时候指定按中间表排序字段排序即可:
c1_products = c1.product_items.order_by('productcategoryrelation__sort_value')
内容的提问来源于stack exchange,提问作者coredumped0x

