我有一个基于django-oscar
(和django-cms
)的项目,该项目使用SITE_ID
模块在具有不同django.contrib.sites
的多个域上运行。该项目已经非常有效,我不能再更改类别标签了-我也希望避免将整个代码切换到“嵌套集树”或“相邻树”中-为了更好地理解:最初的需求并不想进行其他类别排序对于每个域,因此我只使用了Oscars默认类别实现。
但是由于Oscars类别模型/管理器基于django-treebeard
的{{3}}实现,因此我不得不考虑与更改默认顺序的常规Django方法的一些区别。
鉴于模型中的这两个额外字段(继承自django-oscar
的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']
首先,它将忽略此伪指令,因为treebeard
的{{1}}不遵守自定义排序-对于MP_Tree逻辑,它必须依赖在插入时生成的排序(存储在{{ 1}}),因此这种方法会违背MP_Tree本身的目的。
我也看过MP_NodeManager.get_queryset()
-但如materialized path tree所述:
启用
path
时,节点的顺序不正确。订购是 在节点插入时强制执行,因此如果node_order_by
中的属性为 插入节点后修改,树的顺序将是 不一致。
但是同样在具有不同类别顺序的多个域上,这没有用。我唯一能想到的就是重写node_order_by
类:
node_order_by
但是这种方法显然是错误的,因为MP_Tree依靠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')
,忽略最后一部分并进行排序根据{{1}}并将其重新转换为path
。
我什至不确定是否可行,我想避免去那里,所以我的问题是:有没有办法在ORM语句链中反映这种逻辑,以便我可以继续使用本机path
?
答案 0 :(得分:1)
所以这个问题一开始让我非常头疼-我尝试了不同的方法,但没有一个方法令人满意-尝试制作动态排序的MP_Tree在这一点上我会很不鼓励,这太混乱了。最好坚持插入时创建的顺序,并在此阶段使用所有变量。我也要感谢@solarissmoke在评论中提供的帮助。
class Product(AbstractProduct):
# ...
@property
def site_categories(self):
return self.categories.filter(django_site_id=settings.SITE_ID)
@property
def first_category(self):
if not self.site_categories:
return None
return self.site_categories[0]
class Category(AbstractCategory):
# ...
django_site = models.ForeignKey(Site, null=False)
site_rank = models.IntegerField(_('Site Rank'), null=False, default=0)
node_order_by = ['django_site_id', 'site_rank', 'name']
复制templatetags/category_tags#get_annotated_list
进行投影并稍加修改:
# ...
start_depth, prev_depth = (None, None)
if parent:
categories = parent.get_descendants()
if max_depth is not None:
max_depth += parent.get_depth()
else:
categories = Category.get_tree()
# Just add this line
categories = categories.filter(django_site_id=settings.SITE_ID)
# ...
对于templates/catalogue/detail.html
:将{% with category=product.categories.all.0 %}
替换为{% with category=product.first_category %}
您将需要对apps.dashboard
中的视图,表单和表单集进行更改,以照顾新添加的django_site
和site_rank
-我忽略了这一点,因为就我而言,所有通过定期导入的CSV定义类别。这应该没什么大不了的-也许以后我会做,并会更新这个答案。
无论何时添加根节点,子节点或兄弟节点,现在都需要传入django_site_id
参数(以及node_order_by
中包含的所有其他必需值),例如:
parent_category.add_child(
django_site_id=settings.SITE_ID, site_rank=10, name='Child 1')
Category.add_root(
django_site_id=settings.SITE_ID, site_rank=1, name='Root 1')