How can one accomplish class-based default value in following scheme? I mean, I would like to inherited classes set default value for "number" differently:
class OrderDocumentBase(PdfPrintable):
number = models.PositiveIntegerField(default=self.create_number())
@classmethod
def create_number(cls):
raise NotImplementedError
class Invoice(OrderDocumentBase):
@classmethod
def create_number(cls):
return 1
class CreditAdvice(OrderDocumentBase):
@classmethod
def create_number(cls):
return 2
I have looked at this stackoverflow question, but it doesn't address the same problem. The only thing I thought would work was overloading OrderDocumentBase
's __init__
method like this:
def __init__(self, *args, **kwargs):
"""
Overload __init__ to enable dynamic set of default to number
"""
super(OrderDocumentBase, self).__init__(*args, **kwargs)
number_field = filter(lambda x: x.name == 'number', self._meta.fields)[0]
number = self.__class__.create_number()
number_field.default = number
This works, but only partially and behaves quite wierdly. In admin interface, I can see the default being set only after second or latter page refresh. On first try, None
is being set :(
Second possibility is redefinition of number field in each class, but that doesn't seem too much pretty. Is there any other way?
Can someone help?
It does feel nicer to do this via default=, but anything you use there doesn't have a way to get at your class or specific model. To have it show up properly in places like the admin, you could set it in init() instead of save().
class OrderDocumentBase(PdfPrintable):
number = models.PositiveIntegerField()
def __init__(self, *args, **kwargs):
super(OrderDocumentBase, self).__init__(*args, **kwargs)
if not self.pk and not self.number:
self.number = self.DEFAULT_NUMBER
class Invoice(OrderDocumentBase):
DEFAULT_NUMBER = 2
class CreditAdvice(OrderDocumentBase):
DEFAULT_NUMBER = 3
There are a couple of problems here. First, the self.method
is not going to work. There is no self
in the context of the body of the class, which is where you are declaring the PositiveIntegerField
.
Second, passing a callable will not work as the callable gets bound at compile time and does not change at runtime. So if you define say,
class OrderDocumentBase(PdfPrintable):
create_number = lambda: return 0
number = models.PositiveIntegerField(default=create_number)
class Invoice(OrderDocumentBase):
create_number = lambda: return 1
All Invoice
instances will still get 0
as default value.
One way I can think of to tackle this is to override the save()
method. You can check if the number
has not been supplied and set it to a default before saving.
class OrderDocumentBase(PdfPrintable):
number = models.PositiveIntegerField()
def save(self, *args, **kwargs):
if not self.number:
self.number = self.DEFAULT
super(OrderDocumentBase, self).save(*args, **kwargs)
class Invoice(OrderDocumentBase):
DEFAULT = 2
class CreditAdvice(OrderDocumentBase):
DEFAULT = 3
I tested the above with a small change (made OrderDocumentBase
abstract as I did not have PdfPrintable
) and it worked as expected.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With