使用:Django-MySQL

这篇文章是在Django Advent Calendar 2019的第五天发表的。

首先

在Django的ORM中,通过利用select_related、prefetch_related、Prefetch、Q对象等功能,开发者可以轻松发出足够优化的查询。

然而,也有一些不能做到的事情,有时候需要编写原生SQL。比如,当有多个索引时,可以指定要使用的索引,使用 USE_INDEX,或者指定不使用的索引,使用 IGNORE_INDEX等等。这种情况下,需要编写原生SQL。

Django-MySQL:只需要一个选项,在中文中给出以下的释义:

    Django-MySQL

然而,通过使用Django-MySQL,可以扩展Django的ORM而不需要编写生SQL,并能够发出诸如USE_INDEX或IGNORE_INDEX之类的查询。

设置

安装

pip install django-mysql

编辑settings.py

将django-mysql添加到INSTALLED_APPS中。


INSTALLED_APPS = (
    "django.contrib.admin",
    "django.contrib.auth",
    ...
    ...
    "django_mysql",
)

启用DJANGO_MYSQL_REWRITE_QUERIES


DJANGO_MYSQL_REWRITE_QUERIES = True

sql_mode 和 innodb_strict_mode 的配置

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.mysql",
        "HOST": "127.0.0.1",
        "NAME": "hogehoge",
        "USER": "fugafuga",
        "OPTIONS": {
            "charset": "utf8mb4",
            "init_command": "SET sql_mode='STRICT_TRANS_TABLES', innodb_strict_mode=1",
        },
    }
}

如果启用了STRICT模式,尝试插入/更新超过最大长度的数据将会导致错误。如果没有启用STRICT模式,插入/更新超过最大长度的数据将会被截断并进行处理,不会引发错误。因此,如果在进行数据验证时没有做好相应的处理,则需要注意。

此外,这个更改涉及到从Django连接到MySQL时的设置,因此不需要重新进行迁移或其他类似操作。

让我们试一试

模型的设置

用户在应用程序中创建了一个名为hoge的模型。在fuga和piyo两个字段上都添加了索引。

from django.db import models
from django_mysql.models import QuerySet


class Hoge(models.Model):
    fuga = models.IntegerField(db_index=True)
    piyo = models.IntegerField(db_index=True)

    objects = QuerySet.as_manager()

与通常不同的一点是使用from django_mysql.models import QuerySet,并将其用于ORM的管理器。
通过这样做,可以使用Django-MySQL扩展来执行查询。

制作的桌子的信息

mysql> show index from users_hoge;
+------------+------------+--------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table      | Non_unique | Key_name                 | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+------------+------------+--------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| users_hoge |          0 | PRIMARY                  |            1 | id          | A         |           0 |     NULL | NULL   |      | BTREE      |         |               |
| users_hoge |          1 | users_hoge_fuga_8a4fba19 |            1 | fuga        | A         |           0 |     NULL | NULL   |      | BTREE      |         |               |
| users_hoge |          1 | users_hoge_piyo_4539c423 |            1 | piyo        | A         |           0 |     NULL | NULL   |      | BTREE      |         |               |
+------------+------------+--------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

就是这个感觉。

尝试忽略索引。

如果不使用fuga的索引进行查询的情况下,可以按照以下方式进行。

Hoge.objects.all().ignore_index("users_hoge_fuga_8a4fba19")

通过这个操作生成的SQL如下

SELECT
  `users_hoge`.`id`,
  `users_hoge`.`fuga`,
  `users_hoge`.`piyo`
FROM
  `users_hoge` IGNORE INDEX(`users_hoge_fuga_8a4fba19`);

正确地忽略索引已经发行。

另外,如果尝试在不使用Django-MySQL的情况下完成这个任务的话

AttributeError: 'QuerySet' object has no attribute 'ignore_index'

这样会出错。

结束

目前,我只使用过IGNORE INDEX,但还有其他一些有用的功能,比如force index,你可以阅读文档了解更多详细信息。
在通常的ORM中,如果出现无法实现的情况,可能需要通过编写SQL来解决,这时考虑引入Djnago-MySQL可能是一个好的选择。

我想談一下其他的事情。

image.png
广告
将在 10 秒后关闭
bannerAds