Marshall Davis
Marshall Davis

Reputation: 3650

Callable not defined for django.db.models field default

I am using PyCharm 4.5.2, Django 1.8.2.

If I define a class as:

class User(models.Model):
    first_name = models.CharField(max_length=256)
    last_name = models.CharField(max_length=256)
    slug = models.SlugField(max_length=256, unique=True, default=make_slug)

    def make_slug(self):
        return self.first_name + self.last_name[0]

The IDE highlights default=make_slug with make_slug being undefined. The interpretter agrees and when the development server tries to refresh it exits with status 1 and the error NameError: name 'make_slug' is not defined.

Because it's just the name of a callable, I can't pass arguments. So if I define the function outside the class (to move into a higher scope and be defined) I can't use the class properties. I have read some suggestions that use lambdas but from the Django documentation that is wrong:

Note that lambdas cannot be used for field options like default because they cannot be serialized by migrations. See that documentation for other caveats.

What is the proper way to define a callable for default values in a model.

Upvotes: 2

Views: 785

Answers (2)

Alasdair
Alasdair

Reputation: 309099

You get this error

NameError: name 'make_slug' is not defined.

because you refer to make_slug before you defined it. If you moved the make_slug function above the slug field, then you wouldn't get that error.

However, it isn't possible to pass any arguments to the callable that you use as the default, so that won't work either. You can't get around that restriction by using a model method as you are trying.

If you need access to the model instance to calculate the default, then setting the value in the save() method as ruddra suggests is a good idea. Note that you might want to check whether or not the model has a primary key, so that you only create the slug when you first create the instance.

Upvotes: 1

ruddra
ruddra

Reputation: 52028

You shouldn't use this method to set your default value, rather than override the save method of the model and use it there. For example:

class User(models.Model):
    first_name = models.CharField(max_length=256)
    last_name = models.CharField(max_length=256)
    slug = models.SlugField(max_length=256, unique=True, default=uuid.uuid1)

    def make_slug(self):
        return self.first_name + self.last_name[0]

    def save(self, *args, **kwargs):
       self.slug = self.make_slug()
       super().save(*args, **kwargs)

Upvotes: 2

Related Questions