0

I needed to validate a model field to be unique as lower case, but without actually saving the model field in lower case; e.g. if someone has already taken the username 'david', then the username 'David' would not be available. I tried various things, and eventually ended up doing the following:

def _perform_unique_checks(self, unique_checks):
    errors = {}

    for model_class, unique_check in unique_checks:

        lookup_kwargs = {}
        for field_name in unique_check:
            f = self._meta.get_field(field_name)
            lookup_value = getattr(self, f.attname)
            if lookup_value is None:
                continue
            if f.primary_key and not self._state.adding:
                continue
            lookup_kwargs[str(field_name)] = lookup_value

        if len(unique_check) != len(lookup_kwargs):
            continue

        if 'username' in lookup_kwargs:
            lookup_kwargs['username'] = lookup_kwargs['username'].lower()

        qs = model_class._default_manager.filter(**lookup_kwargs)

        model_class_pk = self._get_pk_val(model_class._meta)
        if not self._state.adding and model_class_pk is not None:
            qs = qs.exclude(pk=model_class_pk)
        if qs.exists():
            if len(unique_check) == 1:
                key = unique_check[0]
            else:
                key = NON_FIELD_ERRORS
            errors.setdefault(key, []).append(
                self.unique_error_message(model_class, unique_check))

... which works, but feels a little convoluted to me. I wondered whether any there's a more succinct way of achieving this?

david_hughes
  • 712
  • 2
  • 7
  • 9

2 Answers2

1

Have you tried filtering on field_name__iexact, to do a case insensitive match?

The iregex, icontains and iexact filters should be able to do what you need.

Max Lemieux
  • 584
  • 7
  • 14
0

First off, you can user the clean for this functionality (triggered when trying to validate a form):

def clean__field_name(self):

Also, you can add a unique=True constraint to the field in question. Then do a Try/Except during save to catch any IntegrityError which will tell you that the field is not unique. The database and model should do this work for you instead of trying to code around it.

Also see Case insensitive unique model fields in Django?

With more detail (database type, copy of model, are you using a Form?), I can expand on this answer.

Sina Khelil
  • 2,001
  • 1
  • 18
  • 27