[英]Django/MySQL - __istartswith not producing case-insensitive query
我利用通用视图,并尝试在不区分大小写的庄园中查询我的MySQL数据库(utf8_bin排序规则),以查找所有以特定字母开头的歌曲名称。
view.py
def tracks_by_title(request, starts_with):
return object_list(
request,
queryset = Track.objects.filter(title__istartswith=starts_with),
template_name = 'tlkmusic_base/titles_list.html',
template_object_name = 'tracks',
paginate_by = 25,
)
和我的
urls.py
urlpatterns = patterns('tlkmusic.apps.tlkmusic_base.views',
(r'^titles/(?P<starts_with>\w)/$', tracks_by_title),
)
它根据django调试工具栏生成的查询为:
SELECT `tracks`.`id`, `tracks`.`url`, `tracks`.`artist`, `tracks`.`album`, `tracks`.`genre`, `tracks`.`year`, `tracks`.`title`, `tracks`.`comment`, `tracks`.`tracknumber`, `tracks`.`discnumber`, `tracks`.`bitrate`, `tracks`.`length`, `tracks`.`samplerate`, `tracks`.`filesize`, `tracks`.`createdate`, `tracks`.`modifydate` FROM `tracks` WHERE `tracks`.`title` LIKE a% LIMIT 1
特别是这一行:
WHERE `tracks`.`title` LIKE a% LIMIT 1
为什么我不期望使用__istartswith时不区分大小写?
我在Ubuntu上使用Django 1.1.1。
编辑
在phpmyadmin中运行SELECT * FROM tracks WHERE title LIKE 'a%' LIMIT 0 , 30
0,30仍然返回区分大小写的结果,我想避免更改排序规则,主要是因为数据库由Amarok维护并且我不知道结果更改排序规则的方法。
MySQL不支持ILIKE
。
默认情况下,MySQL的LIKE
不区分大小写地比较字符串。
编辑:
感谢OP提供有关整理的其他信息。
当前的排序utf8_bin
区分大小写。
相反, utf8_general_ci
不区分大小写。
修改归类可能最容易。
像这样:
ALTER TABLE `mydb`.`mytable`
MODIFY COLUMN `song_title` VARCHAR(254)
CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL;
一个解决方案虽然不是我希望/期望的,但仍然有效:
SELECT * FROM tracks WHERE title REGEXP BINARY '^(a|A)';
要使用REGEXP。
这意味着更改我的queryset字符串。
queryset = Track.objects.filter(title__regex=r'^(a|A)'),
不是最佳选择,我将不得不上下查询字符串,然后为数字和非字母数字字符编写一个全新的查询集。
我的解决方案是“扩展”查询集以覆盖某些行为(Django 1.4):
# coding: UTF-8
from django.db.backends.mysql.base import DatabaseOperations as MySqlDatabaseOperations
from django.db.models.query import QuerySet
from django.db.models import sql
from django.db.models.sql.where import WhereNode
class ExtMySqlDatabaseOperations(MySqlDatabaseOperations):
def lookup_cast(self, lookup_type):
if lookup_type in ('iexact', 'icontains', 'istartswith', 'iendswith'):
return "LOWER(%s)"
return super(ExtMySqlDatabaseOperations, self).lookup_cast(lookup_type)
class ExtWhereNode(WhereNode):
def make_atom(self, child, qn, connection):
lvalue, lookup_type, value_annotation, params_or_value = child
if type(connection.ops) in (MySqlDatabaseOperations, ExtMySqlDatabaseOperations):
if lookup_type in ('iexact', 'icontains', 'istartswith', 'iendswith'):
params_or_value = params_or_value.lower()
connection.ops = ExtMySqlDatabaseOperations(connection)
return WhereNode.make_atom(self, (lvalue, lookup_type, value_annotation, params_or_value), qn, connection)
class ExtQuerySet(QuerySet):
def __init__(self, model=None, query=None, using=None):
query = query or sql.Query(model, where = ExtWhereNode)
super(ExtQuerySet, self).__init__(model = model, query = query, using = using)
#self.query = self.query or sql.Query(model, where = ExtWhereNode)
def ext(qs):
return ExtQuerySet(model=qs.model, using=qs._db)
上帝诅咒我,我发现了另一种尴尬的方式。
from django.db.models import Q
queryset = Track.objects.filter(Q(title__startswith=starts_with.upper) | Q(title__startswith=starts_with.lower)),
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.