29

How to set default charfield in lowercase? This is my model:

class User(models.Model):
    username = models.CharField(max_length=100, unique=True)
    password = models.CharField(max_length=64)
    name = models.CharField(max_length=200)
    phone = models.CharField(max_length=20)
    email = models.CharField(max_length=200)

    def __init__(self, *args, **kwargs):
        self.username = self.username.lower()

I tried the __init__ but it doesn't work. I want to make the username in lowercase every time new record saved. Thanks.

v1k45
  • 7,560
  • 2
  • 27
  • 36
Krisnadi
  • 510
  • 1
  • 7
  • 21

4 Answers4

63

While overwriting save() method is a valid solution. I found it useful to deal with this on a Field level as opposed to the Model level by overwriting get_prep_value() method.

This way if you ever want to reuse this field in a different model, you can adopt the same consistent strategy. Also the logic is separated from the save method, which you may also want to overwrite for different purposes.

For this case you would do this:

class NameField(models.CharField):
    def __init__(self, *args, **kwargs):
        super(NameField, self).__init__(*args, **kwargs)

    def get_prep_value(self, value):
        return str(value).lower()

class User(models.Model):
    username = models.CharField(max_length=100, unique=True)
    password = models.CharField(max_length=64)
    name = NameField(max_length=200)
    phone = models.CharField(max_length=20)
    email = models.CharField(max_length=200)
Oran
  • 867
  • 7
  • 13
Danil
  • 2,883
  • 2
  • 17
  • 16
  • 1
    Small typo. SnpField should be NameField. Thank you for this method. I appreciate the reuse-ability. – Anthony Petrillo Jul 07 '19 at 22:03
  • This solution is excellent. I added unique=True to SlugField and lowered it in save(), but I got IntegrityError if the same value passed but not lowercase. your solution helped me overcome it. Thanks – shahwan42 Jun 03 '20 at 15:39
  • +1, this `get_prep_value` method also used when accessing to the DB, e.g. I created an UUID field, that deletes all '-' symbols and do uppercase, then I created an object and trying to get it from the DB: `Unit.objects.get(uuid="dc048edf-a08c41c9-b8a2-10e9-7b8752a8") -> ` – Dmytro Gierman Jul 28 '20 at 07:01
  • 1
    Out of curiosity. Is `get_prep_value` the best function to override when creating `NameField`? In another answer by wiesion, he used `to_python` instead of `get_prep_value`. Any thoughts on that? https://stackoverflow.com/a/50895814/8702081 – Valachio Sep 15 '20 at 05:25
  • 1
    @Valachio according to [this answer](https://stackoverflow.com/questions/31093407/custom-field-in-django-get-prep-value-has-no-effect), "the get_prep_value() only effects what is saved to the DB, not the internal value of the Python object" – rrh Oct 05 '20 at 16:30
  • Should it be something more like: ``` def get_prep_value(self, value): value = value.lower() return super().get_prep_value(value) ``` Also, casting it to a string will cover up any non-string values which are attempted for insertion, which seems bad to me. – Shmuelt Jan 14 '22 at 22:27
32

Just do it in the save method. ie, override the save method of Model class.

def save(self, *args, **kwargs):
    self.username = self.username.lower()
    return super(User, self).save(*args, **kwargs)
Avinash Raj
  • 166,785
  • 24
  • 204
  • 249
  • 7
    It's important to point out this only helps when your model updates go through save. If you write code that does an .update() on a queryset, you don't go through save, so can still end up with uppercase letters in your database field. – aggieNick02 Sep 25 '17 at 14:22
  • @aggieNick02 for this case, a pre_save signal will help. – Avinash Raj Oct 17 '17 at 11:51
  • 8
    No, it does not. The recent edit to this answer should be reverted as it is not correct. From the django docs: "Be aware that the update() method is converted directly to an SQL statement. It is a bulk operation for direct updates. It doesn’t run any save() methods on your models, or emit the pre_save or post_save signals" (source: https://docs.djangoproject.com/en/dev/topics/db/queries/#updating-multiple-objects-at-once) – aggieNick02 Oct 17 '17 at 14:49
  • 1
    Don't override `save`, it'll break other Django methods such as `get_or_create`. – sf89 Jul 24 '19 at 09:50
  • 1
    I found this solution worked fine when you were making new records. But it doesn't work when you are updating existing records. Does anyone know why? – Ross Symonds Sep 30 '20 at 14:51
  • Apologies, I had made a dumb error with my specific code - https://stackoverflow.com/questions/64143480/i-have-over-written-the-save-method-but-the-new-code-is-only-being-applied-to/64143624#64143624 – Ross Symonds Oct 01 '20 at 04:29
  • It would be better to use `to_python` on the field – alias51 Sep 04 '21 at 09:52
  • This not the best way todo this at all.. and the below from #Danil is certainly the preferred nd arguably the more sustainable and reusable – AppHandwerker Sep 05 '21 at 13:11
0

signals also works

from django.db.models.signals import pre_save

@receiver(pre_save, sender=YourModel)
def to_lower(sender, instance=None, **kwargs):
    instance.text = instance.text.lower() if  \
        isinstance(instance.text, str) else ''
sralvins
  • 131
  • 1
  • 4
-2
def save(self, force_insert=False, force_update=False):
        self.YourFildName = self.YourFildName.upper()
        super(YourFomrName, self).save(force_insert, force_update)
Pyro Fury
  • 5
  • 1