django的非外键排序
两张表我需要对part里面的字段进行排序, 但是没有外键关联
class Parts(models.Model):
...
...
...
class LocationDrawerComponentParts(models.Model):
location_drawer_component = models.ForeignKey(
"cews.LocationDrawerComponent", on_delete=models.CASCADE, null=False, blank=False
)
stock_code = models.CharField("Stock code", max_length=255)
serial_no = models.CharField("Serial no", max_length=255)
location_text = models.CharField("Location text", max_length=255, default='')
sequence = models.IntegerField(default=1) # 抽屉里面的摆放顺序
part_id = models.IntegerField(default=0) # 关联parts表的id
created = models.DateTimeField(auto_now_add=True, null=True, blank=True)
updated = models.DateTimeField(auto_now=True, null=True, blank=True)
deleted = models.BooleanField(default=False)
ordering = request.query_params.get("ordering")
if ordering in ["stock_code","-stock_code", "serial_no","-serial_no", "created","-created", "description", "-description" ]:
if ordering in ["description", "-description"]:
part_ids = queryset.values_list("part_id", flat=True)
part_queryset = Parts.objects.filter(id__in=part_ids).order_by(ordering)
ordered_ids = list(part_queryset.values_list('id', flat=True))
preserved_order = Case(
*[When(part_id=id, then=pos) for pos, id in enumerate(ordered_ids)]
)
queryset = queryset.order_by(preserved_order)
else:
queryset = queryset.order_by(ordering)
else:
queryset = queryset.order_by("-id")
这里使用了case来排序
preserved_order = Case(
*[When(part_id=id, then=pos) for pos, id in enumerate(ordered_ids)]
)
在Django ORM中,Case和When是条件表达式,用于构建复杂的查询逻辑。在提供的代码中,它们的作用是根据关联模型(Parts)的排序结果,动态生成主查询集的排序规则,最终实现“通过关联模型字段排序主查询集”的效果。
代码逻辑解析 当排序字段是description或-description时: 先获取主查询集关联的part_id列表。 根据这些part_id查询Parts表,并按description排序,得到一个有序的part对象列表。 通过Case和When,将part对象的顺序映射到主查询集的part_id上,使得主查询集按part.description的顺序排序。 其他排序字段(如stock_code): 直接对主查询集使用order_by(ordering)。 Case和When的作用 Case:表示一个条件表达式块,包含多个When子句。 When:定义条件分支,格式为When(condition, then=value)。 在代码中:
python preserved_order = Case( *[When(part_id=id, then=pos) for pos, id in enumerate(ordered_ids)] ) queryset = queryset.order_by(preserved_order) 生成动态排序规则: 遍历排序后的ordered_ids,为每个id生成一个When条件。 例如,若ordered_ids = [3, 1, 2],则生成的Case表达式为: python Case( When(part_id=3, then=0), When(part_id=1, then=1), When(part_id=2, then=2), ) 最终,主查询集会按照then的值(即0, 1, 2)升序排列,对应的记录顺序为part_id=3 → part_id=1 → part_id=2。 为什么需要这样处理? 间接排序:如果主模型(假设是Product)通过外键part_id关联到Parts,直接在主查询集用order_by("part__description")可能无法满足复杂场景(例如聚合查询或特定过滤)。 控制顺序:通过手动指定ordered_ids的顺序,可以确保主查询集严格遵循Parts模型排序后的顺序。 类比SQL 最终的查询逻辑类似以下SQL:
SELECT * FROM main_table
ORDER BY CASE
WHEN part_id = 3 THEN 0
WHEN part_id = 1 THEN 1
WHEN part_id = 2 THEN 2
END;