Администратор 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)

Результаты/вывод:

Списки коллекций

Collection-lists

Коллекции ID: 1 являются родительскими для коллекций ID: 2 и ID: 4

Идентификатор коллекции: 3 является родительским для идентификатора коллекции: 5

Списки продуктов

Product-lists

Списки продуктов Фильтр по ID коллекции: 1

Filter by collection id: 1

Списки продуктов Фильтр по ID коллекции: 3

Filter by collection id: 3

Списки продуктов Фильтр по ID коллекции: 2

Filter by collection id: 2

Вернуться на верх