【发布时间】:2018-12-04 06:06:37
【问题描述】:
我有一个基于django-oscar(和django-cms)的项目,它使用django.contrib.sites 模块在具有不同SITE_IDs 的多个域上运行。该项目已经富有成效,我不能再更改类别 slug - 我希望避免将整个代码切换到嵌套集树或相邻树 - 为了您更好地理解:初始要求不想要不同的类别排序对于每个域,所以我只使用 Oscars 默认类别实现。
但由于 Oscars 类别模型/经理基于 django-treebeards materialized path tree 实现,我必须考虑与通常的 Django 更改默认排序方式的一些差异。
鉴于模型中的这两个额外字段(继承自 django-oscars AbstractCategory)
class Category(AbstractCategory):
# ...
order_site_1 = models.IntegerField(
null=False,
default=0
)
order_site_2 = models.IntegerField(
null=False,
default=0
)
我不能简单地将排序添加到元类中,例如:
class Category(AbstractCategory):
class Meta:
ordering = ['depth', '-order_site_{}'.format(Site.objects.get_current().id), 'name']
首先,它将忽略此指令,因为treebeards MP_NodeManager.get_queryset() 不尊重自定义排序 - 对于 MP_Tree 逻辑,它必须依赖于插入时生成的排序(存储在 path 中),所以这种方法会违背 MP_Tree 本身的目的。
我也看过node_order_by - 但正如docs中所述:
启用
node_order_by时节点的顺序不正确。订购是 在节点插入时强制执行,所以如果node_order_by中的属性是 插入节点后修改,树排序将是 不一致。
但同样在具有不同类别排序的多个域上,这是没有用的。我能想到的唯一方法是覆盖MP_NodeManager 类:
class CustomOrderQuerySet(MP_NodeManager):
def get_queryset(self):
sort_key = '-order_site_{}'.format(Site.objects.get_current().id)
return MP_NodeQuerySet(self.model).order_by('depth', sort_key, 'name')
但是这种方法显然是错误的,因为 MP_Tree 依赖于path 排序来生成正确的树 - 我想到的是遍历所有条目,比较 path,忽略最后一部分并根据 @987654341 排序@ 并将其重新转换为 QuerySet。
我什至不确定这是否可能,我想避免去那里,所以我的问题是:有没有办法在 ORM 语句链中反映这种逻辑,以便我可以继续使用本机QuerySet?
【问题讨论】:
-
我并没有真正适合您的解决方案,但只想说使用物化路径的全部意义在于提高查询效率。如果您最终覆盖查询集/排序,您将失去这种效率,并且执行基本查询(例如,获取类别及其祖先)很快就会变得非常昂贵。这在奥斯卡已经有些低效了,而且会变得更糟。
-
我完全同意你写的,但正如我所说,现在改变分类系统意味着很多工作,特别是为每个 MP 重定向到新的 NS/AS 是我希望避免的事情,所以我想知道...除此之外,您对如何替换类别系统有什么建议吗?
-
您在同一个数据库上运行了多少个站点/域?
-
目前只有2个,没有第三个或第四个的计划,所以目前不需要完全动态
SITE_ID -
您可以考虑维护两个单独的类别树,每个站点一个。然后,您需要重写一些视图逻辑来确定每个站点使用哪个树,但您不必为各个类别弄乱路径。
标签: django django-oscar django-treebeard