Django queryset с совпадением всех комбинаций

Моя модель:

class Pattern(models.Model):
    name = CICharField("Pattern Name", max_length=200, unique=True)
    symptoms = models.ManyToManyField(Symptom, through='PatternSymptom', related_name='patterns')
    tongue_colour = models.ManyToManyField(Color, verbose_name="Tongue Body Colour", blank=True, related_name='patterns')
    tongue_shape = models.ManyToManyField(Shape, verbose_name="Tongue Body Shape", blank=True, related_name='patterns')
    tongue_quality = models.ManyToManyField(Quality, verbose_name="Tongue Body Features", blank=True, related_name='patterns')

Цвет, форма, качество модели:

class Color(models.Model):
    name = CICharField(max_length=300, unique=True)

На фронт-энде пользователи могут выбрать несколько симптомов, цвет, форму, качество, чтобы найти паттерн, и это будет передано в модель Pattern как symptoms_selected params. У меня есть следующий get_queryset на Pattern > views.py

    def get_queryset(self):
        params = self.request.query_params
        query_symptoms = self.request.GET.getlist('symptoms_selected')
        tongue_colour = self.request.GET.get('tongue_colour')
        tongue_shape = self.request.GET.get('tongue_shape')

        if query_symptoms:
            queryset = Pattern.objects.filter(
                symptoms__id__in=query_symptoms
            ).annotate(
                symptom_matches=Count('symptoms')
            ).annotate(
                pattern_weight=Sum('pattern_to_symptom__priority')
            ).annotate(
                key_count=Count('pattern_to_symptom__priority')
            ).order_by('-matches','-pattern_weight','most_common')
        else:
            queryset = Pattern.objects.all().filter(is_searchable=True)

        if tongue_colour is not None and tongue_colour.isnumeric():
            queryset = queryset.filter(tongue_colour__id__in=tongue_colour).annotate(tongue_color_matches=Count('tongue_colour'));

        if tongue_shape is not None and tongue_shape.isnumeric():
            queryset = queryset.filter(tongue_shape__id__exact=tongue_shape).annotate(tongue_shape_matches=Count('tongue_shape'));

        return queryset

С помощью этого кода я могу получить кверисет с совпадениями симптомов И цвет_языка И форма_языка. Но я хочу показать кверисет с OR/все комбинации с тем, что совпало.

Например: Данные шаблона:

Паттерн A: Симптомы: A, B, C, D Цвет языка: TC1, TC2, TC5 Форма языка: TS1, TS3, TS5

Шаблон B: Симптомы: A, D, P, Q Цвет языка: TC2, TC3, TC6 Форма языка: TS1, TS2, TS6

Паттерн C: Симптомы: A, Q, X, Y Цвет языка: TC1, TC4, TC7 Форма языка: TS1, TS4, TS7

Например, если Пользователи выбирают: 2 симптома: A, Y. Цвет языка: TC1 Форма языка: TS7

Выдает Null. Потому что нет точного совпадения. Вместо Null я хочу показывать пользователям совпадения с любой комбинацией, показывая, какие были совпадения симптомов, цвета, формы и т.д. Я хочу, чтобы queryset возвращал все комбинации:

Искомый результат приведенного выше примера будет выглядеть так:

3 шаблона совпали.

[
    {
        "name": "Pattern A",
        "symptoms_matches": 1,
        "tongue_color_matches": 1,
        "tongue_shape_matches": 0,
    },
    {
        "name": "Pattern B",
        "symptoms_matches": 1,
        "tongue_color_matches": 0,
        "tongue_shape_matches": 0,
    },
    {
        "name": "Pattern C",
        "symptoms_matches": 1,
        "tongue_color_matches": 0,
        "tongue_shape_matches": 1,
    },
]

Я использую Django REST API для передачи данных результата.

class PatternSerializer(serializers.ModelSerializer):

    class Meta:
        model = Pattern
        fields = ('id', 'name', 'symptoms', 'symptoms_matched')

Подобно симптому matched я хочу передать также tongue_color_matched & tongue_shape_matched. Может ли кто-нибудь сказать мне, как я могу этого добиться?

Вы можете использовать Q-объект для того, чтобы выполнить запрос с помощью OR.

from django.db.models import Q 

queryset = Pattern.objects.filter(
    Q(symptoms__id__in=symptom) |
    Q(tongue_shape__id__exact=tongue_shape) |
    Q(tongue_colour__id__in=tongue_colour))
Вернуться на верх