使用: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可能是一个好的选择。