Django MySql Полнотекстовый поиск работает, но не на тестах - PullRequest
0 голосов
/ 28 апреля 2020

Я использовал этот SO вопрос для включения полнотекстового поиска в mysql дБ в Django приложении.

# models.py

class CaseSnapshot(BaseModel):
    text = models.TextField(blank=True)


class Search(models.Lookup):
    lookup_name = "search"

    def as_mysql(self, compiler, connection):
        lhs, lhs_params = self.process_lhs(compiler, connection)
        rhs, rhs_params = self.process_rhs(compiler, connection)
        params = lhs_params + rhs_params
        return f"MATCH (%s) AGAINST (%s IN BOOLEAN MODE)" % (lhs, rhs), params


models.TextField.register_lookup(Search)

Поскольку Django не поддерживает полнотекстовый поиск на mysql мы должны добавить наш индекс, поэтому мы изменим сгенерированный файл миграции:

# Generated by Django 2.2 on 2020-04-28 03:41

from django.db import migrations, models

# Table details
table_name = "by_api_casesnapshot"
field_name = "text"
index_name = f"{table_name}_{field_name}_index"


class Migration(migrations.Migration):

    dependencies = [("by_api", "0033_add_tag_color")]

    operations = [
        migrations.CreateModel(...), # As auto-generated
        migrations.RunSQL(
            f"CREATE FULLTEXT INDEX {index_name} ON {table_name} ({field_name})",
            f"DROP INDEX {index_name} ON {table_name}",
        ),
    ]

Проверка работы

# dbshell

mysql> SHOW INDEX FROM by_api_casesnapshot;

+---------------------+--------------------------------+-------------+-----+------------+-----+
| Table               | Key_name                       | Column_name | ... | Index_type | ... |
+---------------------+--------------------------------+-------------+-----+------------+-----+
| by_api_casesnapshot | PRIMARY                        | id          | ... | BTREE      | ... |
| by_api_casesnapshot | by_api_casesnapshot_text_index | text        | ... | FULLTEXT   | ... |
+---------------------+--------------------------------+-------------+-----+------------+-----+
#shell 
>>> snap = CaseSnapshot.objects.create(text="XXX")

# Regular query first
>>> CaseSnapshot.objects.filter(text__contains="X") 
<QuerySet [<CaseSnapshot pk=1>]>

# Now test custom search lookup
>>> CaseSnapshot.objects.filter(text__search="XXX")
<QuerySet [<CaseSnapshot pk=1>]>

>>> CaseSnapshot.objects.filter(text__search="X*")
<QuerySet [<CaseSnapshot pk=1>]>

>>> CaseSnapshot.objects.filter(text__search="X*").query.__str__()

'SELECT `by_api_casesnapshot`.`id`, `by_api_casesnapshot`.`text` FROM `by_api_casesnapshot` WHERE MATCH (`by_api_casesnapshot`.`text`) AGAINST (X* IN BOOLEAN M
ODE)'

Все, что работает в точности так, как задумано.

Проблема

Здесь все не получается - все запросы, использующие __search lookups во время тестовых прогонов , возвращают пустой набор наборов запросов Я даже думал, что сгенерированный запрос идентичен.

Тесты

from django.test import TestCase
from by_api.models import CaseSnapshot


class TestModels(TestCase):
    def test_search(self):
        CaseSnapshot.objects.create(text="XXX")
        rv1 = CaseSnapshot.objects.filter(text__contains="XXX")
        # Passes
        self.assertEqual(rv1.count(), 1)

        rv2 = CaseSnapshot.objects.filter(text__search="XXX")
        # Fails - count i
        self.assertEqual(rv2.count(), 1)


Я попытался отладить это с помощью pdb в тестовом прогоне, и обратите внимание, что сгенерированный запрос идентичен приведенному выше в среда оболочки:

>>> rv2.query.__str__())
'SELECT `by_api_casesnapshot`.`id`, `by_api_casesnapshot`.`text` FROM `by_api_casesnapshot` WHERE MATCH (`by_api_casesnapshot`.`text`) AGAINST (XXX IN BOOLEAN MODE)'

Вопрос

Почему использование поиска __search во время тестов приводит к пустому набору запросов?

Что Я пытался

  • просмотр mysql стоп-слов, вызывающих пустые запросы * 104 3 *
  • убедитесь, что тестовые базы данных и оболочки db имеют одинаковые значения
  • попытался выполнить произведенный запрос с помощью курсора - также пусто

Обновление

Я только что заметил если я использую unittest.TestCase вместо django.test.TestCase, тесты пройдены - может ли это быть связано с тем, как тестовый пример django оборачивает транзакции в БД?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...