Django MySql全文搜索有效,但不适用于测试 [英] Django MySql Fulltext search works but not on tests

查看:207
本文介绍了Django MySql全文搜索有效,但不适用于测试的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用了这个 SO问题来在mysql数据库中启用全文搜索Django应用程序.

I used this SO question to enable full text search on a mysql db in Django application.

# 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上进行全文搜索,因此我们必须添加索引,因此我们修改了生成的迁移文件:

Because Django does not support full text search on mysql, we have to add our index, so we modify the generated migration file:

# 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查找的所有查询 ,即使认为生成的查询是相同的,也会返回一个查询集空集.

Here is where things fail - all queries using the __search lookups during test runs return an queryset empty set, even thought the generated query is identical.

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进行调试,并注意生成的查询与上面在shell环境中生成的查询相同:

I tried to debug this with pdb inside the test run, and note the generated query is identical to the one produced above in the shell environment:

>>> 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查找会产生空查询集?


Question

Why does use of __search lookup during tests produce empty queryset?

我只是注意到如果我使用unittest.TestCase而不是django.test.TestCase测试通过-这可能与django的测试用例包装数据库事务有关吗?

I just noticed if I use unittest.TestCase instead of django.test.TestCase the test passes - could this be related to how django's test case wraps db transactions?

推荐答案

Adam Chainz的答案frmo django-mysql库:

Answer from Adam Chainz frmo django-mysql library:

在提交之前,InnoDB不会对全文索引进行更改.您可以使用TransactionTestCase来解决此问题.

InnoDB doesn't make changes to full text indexes until commits. You can use TransactionTestCase to get around this.

我将测试类更改为使用TransactionTestCase,现在测试通过了.

I change the test class to use TransactionTestCase and the tests now pass.

这篇关于Django MySql全文搜索有效,但不适用于测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆