Jer
Jer

Reputation: 231

django migrate from CIEmailField to collation

I did upgrade django version to 4.2.8 and then the CIEmailField() is deprecated.

I used this CIEmailField on the email field of an user. So I had to change to:

email = models.EmailField(unique=True, db_collation="case_insensitive")

So the migration is like this:

operations = [
        CreateCollation(
            "case_insensitive",
            provider="icu",
            locale="und-u-ks-level2",
            deterministic=True,
        ),
        migrations.AlterField(
            model_name="user",
            name="email",
            field=models.EmailField(db_collation="case_insensitive", max_length=254),
        ),
    ]

But before this changement, with CIEmailField I would .get() an user with this email "[email protected]" or "[email protected]".

With the case_insensitive collation I made it work only by setting "deterministic=False". But with that, the SQL's LIKE is not working. So every Viewset with "email" in "search_fields" wont work.

To make it work, I only found this solution:

class UserAdmin(BaseUserAdmin):
    search_fields = ("email_deterministic", ...)

    ...

    def get_queryset(self, request: HttpRequest) -> QuerySet[User]:
        return (
            super()
            .get_queryset(request)
            .annotate(
                email_deterministic=Collate("email", "und-x-icu"),
            )
        )

So I have to do that EVERYWHERE on the App when I have an user to search by his email. But the App is big.

Is there any other solution for this?

Upvotes: 1

Views: 153

Answers (1)

Vladimir
Vladimir

Reputation: 23

I ended up using deterministic=True with custom clean method in my user model:

class User(AbstractBaseUser):
    email = models.EmailField(
        unique=True,
        db_collation="case_insensitive",
    )
    # ...
    def save(self, *args, **kwargs):
        self.clean()
        super().save(*args, **kwargs)

    def clean(self):
        super().clean()
        self.email = self.__class__.objects.normalize_email(self.email).lower()

You can also use django-citext package, which was created after discussion in mailing list.

Upvotes: 0

Related Questions