我基本上有一个用户名是唯一的(大小写不敏感),但大小写问题时,显示由用户提供。
本人有以下要求:
- 字段与CharField兼容
- 字段唯一,但不区分大小写
- 字段需要可搜索,忽略大小写(避免使用iexact,容易忘记)
- 字段保存时 shell 完好无损
- 优选地在数据库级上实施
- 优选地避免存储额外的字段
这在 Django 有可能吗?
我想到的唯一解决方案是“以某种方式”覆盖模型管理器,使用一个额外的字段,或者在搜索中总是使用“iexact”。
我使用的是Django 1.3和PostgreSQL 8.4.2。
9条答案
按热度按时间iibxawm41#
从Django 1.11开始,你可以使用CITextField,一个Postgress特有的字段,用于citext类型支持的不区分大小写的文本。
Django还提供了
CIEmailField
和CICharField
,它们是EmailField
和CharField
的不区分大小写的版本。toe950272#
将原始的大小写混合字符串存储在纯文本列中。使用数据类型**
text
**或不带长度修饰符的varchar
,而不是varchar(n)
。它们本质上是相同的,但使用varchar(n)时,必须设置任意长度限制,如果以后要更改,这可能会很麻烦。请阅读有关in the manual或此related answer by Peter Eisentraut @serverfault.SE的更多信息。在
lower(string)
上创建一个functional unique index,这是这里的要点:如果你试图
INSERT
一个混合大小写的名字,而这个名字已经是小写的了,你会得到一个唯一的键冲突错误。对于快速相等搜索,请使用如下查询:
使用与索引中相同的表达式(以便查询计划器识别兼容性),这样会非常快。
顺便说一句:你可能想升级到PostgreSQL的最新版本。已经有很多important fixes since 8.4.2了。更多关于official Postgres versioning site的信息。
lhcgjxsq3#
覆盖模型管理器,你有两个选择,第一个是创建一个新的查找方法:
然后,您使用
get_by_username('blah')
而不是get(username='blah')
,并且不必担心忘记iexact
,当然,这要求您记住使用get_by_username
。第二种选择更加复杂,我甚至不愿提出,但为了完整起见,我将:覆盖
filter
和get
,这样如果您在按用户名查询时忘记了iexact
,它将为您添加它。z8dt9xmd4#
截至2021年12月,在Django 4.0 UniqueConstraint表达式的帮助下,您可以像这样向模型中添加 meta类:
我不是一个专业的Django开发人员,我不知道这个解决方案的技术考虑,如性能问题。希望其他人对此发表评论。
yhxst69z5#
由于用户名总是小写的,建议在Django中使用自定义的小写model字段。为了方便访问和代码整洁,在app文件夹中创建一个新文件
fields.py
。用法(以
models.py
为单位)结束注解:您可以使用此方法在数据库中存储小写值,而不必担心
__iexact
。hpxqektj6#
你可以使用citextpostgres类型来代替,而不用再为任何类型的不精确而烦恼。只需在模型中注明底层字段是不区分大小写的。解决起来容易得多。
mmvthczy7#
您可以在序列化器的UniqueValidator中使用lookup='iexact',如下所示:Django中唯一的模型字段和大小写敏感性(postgres)
zour9fqk8#
我喜欢Chris Pratt的答案,但它对我不起作用,因为
models.Manager
-类没有get(...)
或filter(...)
方法,我不得不通过自定义QuerySet
采取额外的步骤:这在一个非常简单的情况下对我起作用,但到目前为止效果相当不错。
w9apscun9#
您还可以覆盖
get_prep_value()
并通过继承重用它。这样,如果您想在另一个模型中重用这个字段,您可以使用相同的一致策略。
来自Django文档:
一个月一个月一个月二个月
value是模型属性的当前值,并且该方法应该以已准备好用作查询中的参数的格式返回数据。
有关用法,请参见将Python对象转换为查询值。