Django фильтрует объекты, которые содержат значение поля JSON, в списке значений JSONField другой модели с тем же "ключом".

Я не уверен, что название этого поста помогло вам понять суть проблемы, но позвольте мне объяснить:

У меня есть модели:

class ItemCategory(models.Model):
    name = CharField()

class Item(models.Model):
    brand = CharField()
    model = CharField()
    category = ForeignKey(ItemCategory)
    attributes = JSONField(default=dict) # e.g {"size": 1000, "power": 250}

class StockItem(models.Model):
    item = ForeignKey(Item)
    stock = ForeignKey(Stock)
    quantity = PositiveIntegerField()

В этих моделях представлены некоторые товары на складе. Теперь я хочу реализовать функциональность, позволяющую пользователю создавать "абстрактные контейнеры", в которые он может вводить данные и отслеживать, сколько "абстрактных контейнеров" может быть произведено на основе остатков на складе.

Пример:

class Container(models.Model):
    name = CharField()

class ContainerItem(models.Model):
    container = models.ForeignKey(Container)
    item_category = models.ForeignKey(ItemCategory)
    attributes = models.JSONField(default=dict)
    quantity = models.PositiveIntegerField()

Для обработки агрегации я создаю представление:

class ContainerListView(ListView):
    model = models.Container

    def get_queryset(self):
        items_quantity_sq = models.Item.objects.filter(
            item_category=OuterRef('item_category'),
            attributes__contains=OuterRef('attributes'),
        ).values('item_category').annotate(
            total_quantity=Sum('stock_items__quantity')
        ).values('total_quantity')

        min_available_sq = models.ContainerItem.objects.filter(
            container_id=OuterRef('pk')
        ).annotate(
            available=Coalesce(Subquery(items_quantity_sq), Value(0))
        ).order_by('available').values('available')[:1]

        base_qs = super().get_queryset().annotate(
            # Attach the minimum available quantity across all items
            potential=Subquery(min_available_sq)
        ).prefetch_related(
            Prefetch(
                "items",
                queryset=models.ContainerItem.objects.all()
                    .annotate(available=Subquery(items_quantity_sq))
                    .order_by("available"),
            )
        )

        return base_qs.order_by("potential")

Это работает до тех пор, пока ContainerItem attributes поле не содержит одно значение: {"size": 1000} но я хочу разрешить пользователю вводить несколько значений ("size": [1000, 800]), чтобы найти все Item объектов, которые attributes поле (JSONField) содержит "size": 1000 или "size": 800.

Возможно, есть решение, использующее необработанный SQL. Но мне интересно, есть ли вообще правильный дизайн для выполнения такой агрегации в будущем? Может быть, в этом случае EAV может быть лучшим решением?

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