Администратор Django: Фильтрация товаров на основе родительских и дочерних коллекций
Я использую самореферентные отношения в моей модели Django Collection, и я хочу изменить админку, чтобы фильтровать товары на основе коллекции. В настоящее время, когда клиент фильтрует товары по определенной коллекции, он показывает только товары, непосредственно связанные с этой коллекцией, а не с ее дочерними коллекциями. Я изменил функцию get_search_results
в админке, но сгенерированный запрос, похоже, добавляет к моему фильтру условие AND вместо OR.
Вот текущая реализация функции get_search_results:
def get_search_results(self, request, queryset, search_term):
collection_filter = request.GET.get('collection__id__exact')
if collection_filter:
try:
collection_id = int(collection_filter)
collection_q = Q(collection_id=collection_id) | Q(collection__parent_id=collection_id)
queryset = queryset.filter(collection_q)
print(queryset.query)
except ValueError:
pass
print(queryset.query)
return queryset, False
enter code her`
print result :
SELECT "shop_product"."id", "shop_product"."created_at", "shop_product"."updated_at", "shop_product"."deleted_at", "shop_product"."unit_price", "shop_product"."inventory", "shop_product"."min_inventory", "shop_product"."collection_id", "shop_product"."promotions_id", "shop_product"."discount_id", "shop_collection"."id", "shop_collection"."created_at", "shop_collection"."updated_at", "shop_collection"."deleted_at", "shop_collection"."parent_id" FROM "shop_product" INNER JOIN "shop_collection" ON ("shop_product"."collection_id" = "shop_collection"."id") LEFT OUTER JOIN "shop_product_translation" ON ("shop_product"."id" = "shop_product_translation"."master_id") WHERE ("shop_product"."collection_id" = 2 AND ("shop_product"."collection_id" = 2 OR "shop_collection"."parent_id" = 2)) ORDER BY "shop_product_translation"."title" ASC, "shop_product"."id" DESC
Результирующий запрос, похоже, использует условия AND, что может быть причиной отсутствия продуктов дочерних коллекций. Как изменить его, чтобы вместо этого использовать условия OR и обеспечить включение продуктов из родительской и дочерней коллекций в отфильтрованные результаты?
Любая помощь в понимании и решении этой проблемы будет оценена по достоинству.
Этот ответ без использования других библиотек/зависимостей (при использовании Django).
Предположим, что у вас есть структура модели, подобная этой:
class ShopCollection(models.Model):
id = models.AutoField(primary_key=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
deleted_at = models.DateTimeField(null=True, blank=True)
parent = models.ForeignKey("self", on_delete=models.CASCADE, null=True, blank=True)
class Meta:
verbose_name = "Shop Collection"
verbose_name_plural = "Shop Collections"
def __str__(self):
return f"Collection ID: {self.id}"
class ShopProduct(models.Model):
id = models.AutoField(primary_key=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
deleted_at = models.DateTimeField(null=True, blank=True)
unit_price = models.DecimalField(max_digits=10, decimal_places=2)
inventory = models.IntegerField()
min_inventory = models.IntegerField()
collection = models.ForeignKey(
ShopCollection, on_delete=models.CASCADE, related_name="products"
)
promotions = models.ForeignKey(
Promotion, on_delete=models.SET_NULL, null=True, blank=True
)
discount = models.ForeignKey(
Discount, on_delete=models.SET_NULL, null=True, blank=True
)
class Meta:
verbose_name = "Shop Product"
verbose_name_plural = "Shop Products"
def __str__(self):
return f"Product ID: {self.id}"
А вот изменения, которые необходимо внести в ShopProduct ModelAdmin в admin.py:
from django.contrib import admin
from django.db.models import Q
from .models import ShopProduct, ShopProductTranslation
from collection.models import ShopCollection
class CollectionFilter(admin.SimpleListFilter):
title = "Collection"
parameter_name = "collection"
def lookups(self, request, model_admin):
return ShopCollection.objects.values_list("id", "id")
def queryset(self, request, queryset):
if self.value():
try:
collection_id = self.value()
queryset = queryset.filter(
Q(collection_id=collection_id)
| Q(collection__parent_id=collection_id)
).distinct()
except ShopCollection.DoesNotExist:
pass
return queryset
class ShopProductAdmin(admin.ModelAdmin):
list_display = (
"id",
"collection",
"unit_price",
"inventory",
"min_inventory",
"promotions",
"discount",
"created_at",
"updated_at",
"deleted_at",
)
list_filter = (
CollectionFilter, # Add the custom filter here
"promotions",
"discount",
"created_at",
"updated_at",
"deleted_at",
)
search_fields = ("id",)
ordering = ("id",)
admin.site.register(ShopProduct, ShopProductAdmin)
Результаты/вывод:
Списки коллекций
Коллекции ID: 1 являются родительскими для коллекций ID: 2 и ID: 4
Идентификатор коллекции: 3 является родительским для идентификатора коллекции: 5
Списки продуктов
Списки продуктов Фильтр по ID коллекции: 1
Списки продуктов Фильтр по ID коллекции: 3
Списки продуктов Фильтр по ID коллекции: 2