我希望能够搜索一个产品,其类别不直接链接到它,但该类别是祖父或曾祖父等等,在实际链接到产品本身的类别的类别树上。 我可以实现的唯一方法是使用以下方法,这当然是不可扩展的和正确的方法:
def get_queryset(self, request):
queryset = super().get_queryset(request).select_related('brand', 'category', 'category__parent')
category_name = request.GET.get('category__name', None)
if category_name:
# Filter the queryset to include products with the specified category or its ancestors
queryset = queryset.filter(
Q(category__name=category_name) |
Q(category__parent__name=category_name) |
Q(category__parent__parent__name=category_name) |
# Add more levels as needed based on the depth of your category tree
)
return queryset
这是目前的代码:
Product``models.py
class Product(models.Model):
name = models.CharField(max_length=255)
slug = models.SlugField(blank=True, null=True)
description = models.TextField()
price = models.DecimalField(max_digits=10, decimal_places=2)
image = models.ImageField(upload_to='product_images/')
category = models.ForeignKey(Category, on_delete=models.SET_NULL,related_name='product_category', null=True, blank=True)
brand = models.ForeignKey(Brand, on_delete=models.SET_NULL, related_name='product_brand', null=True, blank=True)
tags = GenericRelation(TaggedItem, related_query_name='product')
ratings = GenericRelation(Rating, related_query_name='product')
active = models.BooleanField(default=True)
timestamp = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
state = models.CharField(max_length=2, choices=PublishStateOptions.choices, default=PublishStateOptions.DRAFT)
publish_timestamp = models.DateTimeField(
# means that the publish_timestamp field will not automatically be set to the current date and time when a new instance of this model is created.
auto_now_add=False,
# means that the publish_timestamp field will not automatically be updated to the current date and time every time the model is saved.
auto_now=False,
blank=True,
null=True
)
def __str__(self):
return self.name
Category``models.py
class Category(models.Model):
name = models.CharField(max_length=255)
parent = models.ForeignKey('self', on_delete=models.SET_NULL, related_name='subcategories', null=True, blank=True)
class Meta:
verbose_name_plural = 'Categories'
def __str__(self):
return self.name
Product``admin.py
class ProductAdmin(admin.ModelAdmin):
list_display = ['name', 'price', 'brand', 'category']
inlines = [TaggedItemInline]
list_filter = [
'brand__name',
'category__name'
]
search_fields = ['name', 'price', 'brand__name', 'category__name', 'category__parent__name']
def get_queryset(self, request):
return super().get_queryset(request).select_related('brand', 'category', 'category__parent')
def get_brand_name(self, obj):
return obj.brand.name if obj.brand else None
def get_category_name(self, obj):
return obj.category.name if obj.category else None
get_brand_name.short_description = 'Brand'
get_category_name.short_description = 'Category'
# Define the labels for list filters
list_filter = (
('brand', admin.RelatedOnlyFieldListFilter),
('category', admin.RelatedOnlyFieldListFilter),
)
admin.site.register(Product, ProductAdmin)
一个小时后,我明白了。
def get_search_results(self, request, queryset, search_term):
queryset, use_distinct = super().get_search_results(request, queryset, search_term)
# Search for products based on ascendant category names recursively
matching_categories = self.find_matching_categories(search_term)
ascendant_categories = self.get_all_ascendant_categories(matching_categories)
products_with_ascendant_categories = self.model.objects.filter(category__in=ascendant_categories)
queryset |= products_with_ascendant_categories
return queryset, use_distinct
def find_matching_categories(self, search_term):
# Find categories that match the search term
return Category.objects.filter(name__icontains=search_term)
def get_all_ascendant_categories(self, categories):
# Recursively retrieve all ascendant categories
ascendant_categories = list(categories)
new_ascendants = Category.objects.filter(parent__in=categories)
if new_ascendants:
ascendant_categories.extend(self.get_all_ascendant_categories(new_ascendants))
return ascendant_categories
当用户搜索产品时,他们现在可以使用该产品类别的上级名称。 get_search_results() 方法经过定制以实现此目的。当用户搜索时,代码会识别与搜索词匹配的类别,然后递归地收集这些类别的所有祖先。这可确保搜索结果中包含类别及其后代的产品。