Reputation: 929
I've found many similar posts on the web about this topic but no one state clearly which is the problem.
Code
class Item(models.Model):
@classmethod
def get_next_item_number(cls):
return cls.objects.count() + 1
number = models.IntegerField(default=get_next_item_number)
Problem
When I access Django admin panel the text field related to 'number' field contains
<classmethod object at 0x7fab049d7c50>
So I tried to change the code above
class Item(models.Model):
@classmethod
def get_next_item_number(cls):
return cls.objects.count() + 1
number = models.IntegerField(default=get_next_item_number())
but when I run django server I get:
number = models.IntegerField(default=get_next_item_number())
TypeError: 'classmethod' object is not callable
I know all this could be prevented by declaring get_next_item_number() as an external function but this solution is not elegant to me because get_next_item_number() refer only to Item class.
Is there a solution I'm missing?
Upvotes: 8
Views: 3171
Reputation: 929
I found this solution:
Code
class Item(models.Model):
@staticmethod
def get_next_item_number():
return Item.objects.count() + 1
number = models.IntegerField(default=get_next_item_number.__func__)
I'm not completely aware of the possible consequences, but it works.
Upvotes: 6
Reputation: 5193
Overwrite __init__
method of your Item
class and assing the default value there, have a look to this code:
from django.db import models
class Item(models.Model):
number = models.IntegerField()
@classmethod
def get_next_item_number(cls):
return cls.objects.count() + 1
def __init__(self, *args, **kwargs):
super(Item, self).__init__(*args, **kwargs)
if not self.pk and not self.number:
self.number = Item.get_next_item_number()
And here's the flow output
>>> from your_app import models
>>> models.Item().save()
>>> models.Item().number
>>> 2
>>> models.Item().save()
>>> models.Item().number
>>> 3
>>> models.Item.objects.filter(id=1)[0].number #number only get its value from classmethod on new items
>>> 1
Upvotes: 0