Django:使用 mptt-django 将产品分配到 many-to-many 关系中的类别

Django: using mptt-django to allocate products to categories in a many-to-many relationship

我在产品和类别之间有 many-to-many 关系。我正在使用 mptt 来管理管理员上的类别显示(效果很好),因此我可以将产品分配给类别。

虽然类别工作正常,但我在产品方面遇到了问题。

在我的 models.py 我有(为简洁起见被截断):

from mptt.models import MPTTModel,TreeForeignKey,TreeManyToManyField

class ProductCategory(MPTTModel):
    parent = TreeForeignKey('self', null=True, blank=True)

class Product(models.Model)
    categories = TreeManyToManyField(ProductCategory)

在我的 admin.py 我有

from django.forms import CheckboxSelectMultiple
from .models import Product,ProductCategory
from django.db import models
from django.contrib import admin
from mptt.admin import MPTTModelAdmin
from mptt.models import TreeManyToManyField

class ProductAdmin(admin.ModelAdmin):

   formfield_overrides = {
      TreeManyToManyField:{'widget':CheckboxSelectMultiple},
   }

这几乎可以完成工作,但所有类别都显示有复选框,这不是我想要的,因为您不想将产品添加到具有子类别的类别。

我想要的是类别的显示,这样您只能将产品添加到没有 children 的类别中,所以在这个例子中

Category 1
Category 2 sub sub 
Category 3 sub

标签将是

Category 1
Category 2 > Catgory 2 sub > Category 2 sub sub
Category 3 > Category 3 sub

非常感谢您的帮助!

更新

嗨,我知道我的问题可能太宽泛了!

作为 Django 新手,我想我需要做的是创建一个自定义小部件,可能会覆盖 CheckboxSelectMultiple 小部件,我可以将其应用于我的 'categories' 模型属性。

目前,我正在使用 formfield_overrides 作为上面讨论的 TreeManyToManyField

formfield_overrides = {
    TreeManyToManyField:{'widget':CheckboxSelectMultiple},
}

这不仅没有给出预期的结果,而且还没有对所有 TreeManyToMany 字段使用标准的 CheckboxSelectMultiple,我可以只为我的 'categories' 属性指定这个小部件吗?

尽管如此,是否可以向我展示如何创建自定义小部件,传递有关类别树和选定状态的信息(对于已分配给类别的产品)?我一直试图自己解决这个问题,但一直在努力 - 非常感谢任何帮助!

根据 KARANTSTHR 评论进行更新

这是类别的屏幕截图 - 显示没有 children 的类别都很好,但是我们可以像上面描述的那样在标签中显示这些类别的 parents 吗?

KARANTSTHR 更新 2

这是您的实施的屏幕截图。

ModelAdmin 非常灵活,您可以在 ProductAdmin 中为 form 选项指定自定义 ModelForm(form 是 ModelAdmin 选项)以过滤掉没有任何子类别的类别。
所以, 我认为您不需要自定义小部件来解决您的问题,只需将 admin.py 更改为

from django import forms
from django.forms import CheckboxSelectMultiple
from .models import Product,ProductCategory
from django.contrib import admin
from mptt.admin import MPTTModelAdmin
from mptt.models import TreeManyToManyField


class filterCategories(forms.ModelForm):
    class Meta:
        model = Product
        fields = '__all__'

    def __init__(self,*args,**kwargs):
        super(filterCategories, self).__init__(*args,**kwargs)
        self.fields['categories'].queryset = ProductCategory.objects.filter(children=None)


class ProductAdmin(admin.ModelAdmin):
    form = filterCategories
    formfield_overrides = { TreeManyToManyField:{'widget':CheckboxSelectMultiple},}


admin.site.register(Product,ProductAdmin)
admin.site.register(ProductCategory,MPTTModelAdmin)


更新 1
您需要在 models.py
的 ProductCategory class 的父字段中添加 related_name 因此 models.py 中的 ProductCategory class 将如下所示

class ProductCategory(MPTTModel):
    name = models.CharField(max_length=100)
    parent = TreeForeignKey('self', null=True, blank=True, related_name='children')

    def __str__(self):
        return self.name

更新 2
您可以更改 ProductCategory 的 str 方法,如下所示用于标签

def __str__(self):
    try:
        ancestors = self.get_ancestors(include_self=True)
        ancestors = [i.name for i in ancestors]
    except:
        ancestors = [self.name]

    return ' > '.join(ancestors[:len(ancestors) + 1])

请注意,这不是获取您选择的标签(对象名称)的激进方法,如果我找到更好的解决方案,我会更新我的答案。