我有以下模型:
class Page(Model):
book = ForeignKey(Book, on_delete=CASCADE)
page = IntegerField()
start = CharField(max_length=350, db_index=True)
end = CharField(max_length=350, db_index=True)
如何查询数据库以获取“包含”给定单词的页面?
page1 = Page.objects.create(start='beaver', end='brother')
page2 = Page.objects.create(start='boy', end='brother')
block
按字母顺序在海狸之后和兄弟。搜索应该不区分大小写。
因此,我需要编写一个查询以获取所有行,其中start
的字母顺序比给定单词小,而end
的字母顺序比给定单词大。
答案 0 :(得分:1)
您可以将end
和start
转换为小数。
在模型中,使用DecimalField
代替CharField
。
然后您可以使用ascii表转换您的单词。
例如,“爱”将转换为: 108111118101
因此在数据库中,其值应为: 0.108111118101(值应小于1,以使单词的长度不会影响过滤。)
“爱慕”将转换为: 97109111117114
请注意,“ a”的ASCII码只有2位数字,并且所有字母必须具有相同的数字位数(此处为3),因此,请在这种情况下用0填充: 0.097109111117114
然后使用小于(lt)大于(gt)的值很容易查询小数是否在小数位之间
注释:
您可以使用模型的getter和setter将单词转换为ascii值,反之亦然。
将单词转换为小写,否则将无法与ascii表一起使用,因为“ C”的值不同于“ c”的值
使用ascii表不适用于拉丁字母中不存在的内容。例如,ç,é,à,è,ù可能会破坏搜索,您应该考虑建立自己的表格,或者将这些字母替换为其基本字母...
现在让我们看看“ django”是否介于“爱情”和“爱情”之间:
love : 0.108111118101
django : 0.100106097110103111
amour : 0.097109111117114
是的:)
答案 1 :(得分:1)
一种选择是在保存之前将start
和end
的所有数据库值转换为大写或小写。然后使用__gte
和__lte
过滤器进行搜索(将搜索词也转换为大写或小写之后)。
它似乎对我有用(使用Python 3.6
,Django 2.2
,postresql 10
):
# create with lowercase words
Page.objects.create(start='beaver', end='brother')
Page.objects.create(start='boy', end='brother')
# filter using lowercase as well
v = request.GET.get('search_term', '').lower()
qs = Page.objects.filter(start__lte=v, end__gte=v)
还是我误解了你的问题?
答案 2 :(得分:0)
我的答案仅适用于Postgresql,但这可能是一种解决方案:
使用postgresql的Django在CICharField
中有一个django.contrib.postgres.fields
模型字段。这也支持对不区分大小写的字符串进行索引。字符串仍将以正确的大小写存储,但是比较操作将不区分大小写。
from django.contrib.postgres.field import CICharField
class Page(Model):
book = ForeignKey(Book, on_delete=CASCADE)
page = IntegerField()
start = CICharField(max_length=350, db_index=True)
end = CICharField(max_length=350, db_index=True)
这应该可以解决您的问题,您将可以使用gte
和lte
过滤器,并且比较将不区分大小写。根据数据库中的设置,它应该可以很好地处理unicode。
t1 = "breast"
t2 = "beast"
t3 = "block"
page1 = Page.objects.create(start='beaver', end='brother')
page2 = Page.objects.create(start='boy', end='brother')
Page.objects.filter(start__lte=t1, end__gte=t1) # <QuerySet [<Page: Page start=beaver, end=brother>, <Page: Page start=boy, end=brother>]>
Page.objects.filter(start__lte=t2, end__gte=t2) # <QuerySet []>
Page.objects.filter(start__lte=t3, end__gte=t3) # <QuerySet [<Page: Page start=beaver, end=brother>]>
t4 = "Ù" # Between Ø and Ú
t5 = "Ü" # Not between Ø and Ú
page3 = Page.objects.create(start='Ø', end='Ú')
Page.objects.filter(start__lte=t4, end__gte=t4) # <QuerySet [<Page: Page start=Ø, end=Ú>]>
Page.objects.filter(start__lte=t5, end__gte=t5) # <QuerySet []>
此更改将生成一个迁移,该迁移将CITextExtension()
安装在数据库上并更改列。您可能需要将该迁移文件分为两个迁移,其中第一个将安装CITextExtension
,第二个将修改您现有的列。