Skip to content

Instantly share code, notes, and snippets.

@jourdanrodrigues
Last active October 11, 2025 15:24
Show Gist options
  • Select an option

  • Save jourdanrodrigues/fcf8ecc4261860eab3bea0d032322565 to your computer and use it in GitHub Desktop.

Select an option

Save jourdanrodrigues/fcf8ecc4261860eab3bea0d032322565 to your computer and use it in GitHub Desktop.
from django.db import models
from django.db.models.functions import Lower
def email_domain_func(value: models.F):
"""
Deliberately avoided class inheritance from `models.Func` to have each value explicitly defined
in the migrations adding indexes.
If they ever change, a new migration will be triggered as it should.
"""
return models.Func(
Lower(value),
models.Value("@"),
models.Value(2),
function="split_part",
output_field=models.CharField(),
)
class DomainLookup(models.Lookup):
lookup_name = "domain"
def __init__(self, lhs, rhs):
if isinstance(rhs, str):
rhs = rhs.lower()
elif isinstance(rhs, models.F):
rhs = Lower(rhs)
super().__init__(lhs, rhs)
def as_sql(self, compiler, connection):
lhs_sql, lhs_params = email_domain_func(self.lhs).as_sql(compiler, connection)
rhs_sql, rhs_params = self.process_rhs(compiler, connection)
return f"{lhs_sql} = {rhs_sql}", lhs_params + rhs_params
models.EmailField.register_lookup(DomainLookup)
# Model
class User(models.Model):
email = models.EmailField(unique=True)
class Meta:
indexes = [
models.Index(
email_domain_func(models.F("email")), name="user_email_domain_idx"
),
]
# Example
User.objects.filter(email__domain="example.com")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment