Как лучше оформить запрос фильтра Django для +1000 записей, используя базу данных SQLite3? (Дерево выражений слишком большое (максимальная глубина 1000))
Модели Django, которые у меня есть, это Component и Product. Компоненты имеют Products в качестве внешнего ключа. Я получаю параметр поиска из request.GET, называемый "components", который содержит список подстрок, которые могут принадлежать любому Компоненту. На основе найденных Компонентов я хочу получить все Продукты, которые имеют этот Компонент, и вернуть их обратно клиенту. В моей базе данных SQLite примерно 12000 Компонентов и 3000 Продуктов
Я отфильтровывал продукты с помощью оператора "|" для каждого id номера продукта компонента, что отлично работает при поиске определенных подстрок компонента, таких как "Lactose" и "Bacterium"
Однако, когда я ищу более короткие подстроки, такие как "ac", я получаю ошибку: "OperationalError at /search, Expression tree is too large (maximum depth 1000)".
Насколько я могу понять, это происходит потому, что база данных выполняет множество запросов на объединение, и более 1000 таких запросов вызывают эту ошибку.
Я хотел бы узнать, как исправить или обойти эту ошибку. Есть ли лучший способ использовать фильтрующие запросы Django?
Вот мой models.py:
from django.db import models
class Product(models.Model):
id_number = models.IntegerField(primary_key=True)
product_name = models.CharField(max_length=200)
class Component(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
name = models.CharField(max_length=200)
Вот мой отрывок из файла views.py:
query = Product.objects.all()
if 'components' in request.GET and len(request.GET['components']) > 0:
component_queries = request.GET['components'].strip().split(",") # List of all components as strings
components = Component.objects.all() # Roughly 12000 entries in total, roughly 1700 entries for a worst case after filtering
for component_query in component_queries:
components &= (Component.objects.filter(name__icontains=component_query)
if len(components) == 0:
query = Product.objects.none()
specified_products = Product.objects.none()
for component in components:
specified_products |= Product.objects.filter(id_number__icontains=component.product.id_number)
query &= specified_products
Чтобы убедиться, что ошибка была в отрывке, я ограничил количество компонентов в цикле for менее 1000, и поисковая система работала нормально.
Вы можете фильтровать с помощью:
from django.db.models import Q
component_queries = request.GET['components'].strip().split(',')
Product.objects.filter(
Q(*[
Q(component__name__icontains=component_query)
for component_query in component_queries
])
)
Вышеуказанное, однако, будет извлекать только те Product
, которые имеют компонент, соответствующий all component_query
s.
Если вы хотите найти продукты, у которых есть хотя бы один компонент, для которого строка совпадает, вы работаете с:
from django.db.models import Q
component_queries = request.GET['components'].strip().split(',')
Product.objects.filter(
Q(*[
Q(component__name__icontains=component_query)
for component_query in component_queries
],
_connector=Q.OR
)
).distinct()
В .distinct()
[Django-doc] будет предотвращено извлечение Product
столько раз, сколько есть совпадающих компонентов.