Coverage for app/venv/lib/python3.14/site-packages/weblate/utils/fields.py: 100%
26 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 07:15 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 07:15 +0000
1# Copyright © Michal Čihař <michal@weblate.org>
2#
3# SPDX-License-Identifier: GPL-3.0-or-later
5from __future__ import annotations
7from typing import ClassVar
9from django.db import models
10from django.utils.translation import gettext_lazy
12from weblate.trans.defines import EMAIL_LENGTH
13from weblate.utils import forms
14from weblate.utils.validators import validate_email
17class CaseInsensitiveField(models.CharField):
18 """Field mixin that uses case-insensitive lookup alternatives if they exist."""
20 LOOKUP_CONVERSIONS: ClassVar[dict[str, str]] = {
21 "exact": "iexact",
22 "contains": "icontains",
23 "startswith": "istartswith",
24 "endswith": "iendswith",
25 "regex": "iregex",
26 }
28 def get_lookup(self, lookup_name):
29 converted = self.LOOKUP_CONVERSIONS.get(lookup_name, lookup_name)
30 return super().get_lookup(converted)
33class UsernameField(CaseInsensitiveField):
34 pass
37class EmailField(CaseInsensitiveField):
38 default_validators = [validate_email] # noqa: RUF012
39 description = gettext_lazy("E-mail")
40 default_error_messages = { # noqa: RUF012
41 "unique": gettext_lazy("A user with this e-mail already exists."),
42 }
44 def __init__(self, *args, **kwargs) -> None:
45 kwargs.setdefault("max_length", EMAIL_LENGTH)
46 super().__init__(*args, **kwargs)
48 def deconstruct(self):
49 name, path, args, kwargs = super().deconstruct()
50 # We do not exclude max_length if it matches default as we want to change
51 # the default in future.
52 return name, path, args, kwargs
54 def formfield(self, **kwargs): # type: ignore[override]
55 # As with CharField, this will cause email validation to be performed
56 # twice.
57 return super().formfield(
58 **{
59 "form_class": forms.EmailField,
60 **kwargs,
61 }
62 )