現在、django.contrib.authには、ユーザー名「john」と「John」の2人のユーザーがいる可能性があります。どうすればこれを防ぐことができますか。
最も簡単なアプローチは、contib.auth.modelsにクリーンなメソッドを追加し、保存する前に小文字に変換することですが、contrib.authパッケージを編集したくありません。
ありがとう。
現在、django.contrib.authには、ユーザー名「john」と「John」の2人のユーザーがいる可能性があります。どうすればこれを防ぐことができますか。
最も簡単なアプローチは、contib.auth.modelsにクリーンなメソッドを追加し、保存する前に小文字に変換することですが、contrib.authパッケージを編集したくありません。
ありがとう。
モデルを聞いてpre_save
、Users
そこでチェックを行います。邪魔にならず、最もポータブルな方法。
これがどのように見えるかの例を次に示します(ユーザープロファイルの例から採用)。
def username_check(sender, instance, **kwargs):
if User.objects.filter(username=instance.username.lower()).count():
raise ValidationError('Duplicate username')
pre_save.connect(username_check, sender=User)
Postgresを使用している場合は、より良いオプションがあります。Postgresには、大文字と小文字を区別しないフィールドタイプがありcitext
ます。1.11の時点で、Djangoではこれをで利用できますdjango.contrib.postgres.fields.citext
。また、URL正規表現で大文字と小文字を区別する必要がある場合もあります。
ユーザー名のカスタムフィールドを使用して、モデルでこれを解決する可能性があります。
from django.db import models
class LowercaseCharField(models.CharField):
"""
Override CharField to convert to lowercase before saving.
"""
def to_python(self, value):
"""
Convert text to lowercase.
"""
value = super(LowercaseCharField, self).to_python(value)
# Value can be None so check that it's a string before lowercasing.
if isinstance(value, str):
return value.lower()
return value
そして、あなたのモデルで。
from django.contrib.auth.models import AbstractUser
from django.contrib.auth.validators import UnicodeUsernameValidator
from django.utils.translation import gettext_lazy as _
# Assuming you saved the above in the same directory in a file called model_fields.py
from .model_fields import LowercaseCharField
class User(AbstractUser):
username = LowercaseCharField(
# Copying this from AbstractUser code
_('username'),
max_length=150,
unique=True,
help_text=_('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.'),
validators=[UnicodeUsernameValidator(),],
error_messages={
'unique': _("A user with that username already exists."),
},
)
# other stuff...
ユーザー名はすべて小文字で「自動的に」保存されます。
受け入れられた回答を最新のものに更新します。
from django.db.models.signals import pre_save
from django.db.utils import IntegrityError
from django.dispatch import receiver
@receiver(pre_save, sender=User)
def username_check(instance, sender, **kwargs):
"""Ensure that username unique constraint is case insensitive"""
if sender.objects.filter(username__iexact=instance.username.lower()):
raise IntegrityError("Duplicate username")