I'm looking for right ways to override the create() method of a subclass.
Basically I'm doing this:
class Base(models.Model):
field1_base = models.IntegerField()
def __init__(self, field1_base):
# LOGICS
self.field1_base = field1_base
class A(Base):
field2_sub = models.IntegerField()
def __init__(self, field2_sub, field1_base):
# LOGICS
self.field2_sub = field2_sub
super(A, self).__init__(field1_base)
A(field2_sub=1, field1_base=2)
However we can't override the __init__() method of a model.
I just want to leave some fields to be assigned in base class's methods.
Is there a proper way to do this using create() method?
Of course I can custom create method of Base class, however what I want is to invoke Base.create and A.create at the same time on the creation of A, which makes the situation different from this question
I would do something like this.
class Base(models.Model):
field1_base = models.IntegerField()
def initialize(self, *args, **kwargs):
self.field1_base = kwargs['field1_base']
#classmethod
def create(cls, *args, **kwargs):
# LOGICS
self = cls()
self.initialize(*args, **kwargs)
return self
class A(Base):
field2_sub = models.IntegerField()
def initialize(self, *args, **kwargs):
super(A, self).initialize(*args, **kwargs)
self.field2_sub = kwargs['field1_base']
A.create(field2_sub=1, field1_base=2)
Related
I have the following models (Here, we are using a class attribute):
class Foo(models.Model):
...
def some_function(self, some_condition):
if some_condition:
# Do something
class Bar(models.Model):
...
foo = models.ForeignKey(Foo)
_some_condition = False # Class attribute
def save(self, *args, **kwargs):
# Do something that sets the `_some_condition` class
# attribute based on some conditions
self.foo.some_function(self._some_condition)
super(Bar, self).save(*args, **kwargs)
In short, my Bar class has a class attribute called _some_condition. This is set in the save function, and then used to call the Foo class's some_function() method.
I can also over-ride the __init__() method and set the _some_condition as an instance attribute. Like so (Here, we are using an instance attribute):
class Bar(models.Model):
...
def __init__(self, *args, **kwargs):
super(Bar, self).__init__(*args, **kwargs)
self._some_condition = False # Instance attribute
...
What even is the difference between the two? I'm generally confused about class and instance attributes in Python.
After doing it both ways for the same model, and testing it in the shell, it seems there is no difference at all between class attributes and instance attributes. Can anyone explain this? The following is the code I used to test both ways:
class MyClass(models.Model):
name = models.CharField(max_length=255)
_class_attr = ''
def __init__(self, *args, **kwargs):
super(MyClass, self).__init__(*args, **kwargs)
self._instance_attr = ''
def save(self, *args, **kwargs):
# Update both before saving
self._class_attr = 'Class attribute'
self._instance_attr = 'Instance attribute'
super(MyClass, self).save(*args, **kwargs)
Results:
>>> from myapp.models import MyClass
>>> MyClass.objects.create(name='first')
<MyClass: MyClass object (1)>
>>> MyClass.objects.create(name='second')
<MyClass: MyClass object (2)>
>>> first = MyClass.objects.get(pk=1)
>>> second = MyClass.objects.get(pk=2)
>>> first._class_attr
''
>>> first._instance_attr
''
>>> second._class_attr
''
>>> second._instance_attr
''
>>> first.save()
>>> first._class_attr
'Class attribute'
>>> first._instance_attr
'Instance attribute'
>>> second._class_attr
''
>>> second._instance_attr
''
I have an object that need to be instantiated ONLY ONCE. Tried using redis for caching the instance failed with error cache.set("some_key", singles, timeout=60*60*24*30) but got serialization error, due the other thread operations:
TypeError: can't pickle _thread.lock objects
But, I can comfortably cache others instances as need.
Thus I am looking for a way to create a Singleton object, I also tried:
class SingletonModel(models.Model):
class Meta:
abstract = True
def save(self, *args, **kwargs):
# self.pk = 1
super(SingletonModel, self).save(*args, **kwargs)
# if self.can_cache:
# self.set_cache()
def delete(self, *args, **kwargs):
pass
class Singleton(SingletonModel):
singles = []
#classmethod
def setSingles(cls, singles):
cls.singles = singles
#classmethod
def loadSingles(cls):
sins = cls.singles
log.warning("*****Found: {} singles".format(len(sins)))
if len(sins) == 0:
sins = cls.doSomeLongOperation()
cls.setSingles(sins)
return sins
In the view.py I call on Singleton.loadSingles() but I notice that I get
Found: 0 singles
after 2-3 requests. Please what is the best way to create Singleton on Djnago without using third party library that might try serialising and persisting the object (which is NOT possible in my case)
I found it easier to use a unique index to accomplish this
class SingletonModel(models.Model):
_singleton = models.BooleanField(default=True, editable=False, unique=True)
class Meta:
abstract = True
This is my Singleton Abstract Model.
class SingletonModel(models.Model):
"""Singleton Django Model"""
class Meta:
abstract = True
def save(self, *args, **kwargs):
"""
Save object to the database. Removes all other entries if there
are any.
"""
self.__class__.objects.exclude(id=self.id).delete()
super(SingletonModel, self).save(*args, **kwargs)
#classmethod
def load(cls):
"""
Load object from the database. Failing that, create a new empty
(default) instance of the object and return it (without saving it
to the database).
"""
try:
return cls.objects.get()
except cls.DoesNotExist:
return cls()
The code below simply prevents the creation of a new instance of the Revenue model if one exists. I believe this should point you in the right direction.
Best of luck !!!
class RevenueWallet(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
class Meta:
verbose_name = "Revenue"
def save(self, *args, **kwargs):
"""
:param args:
:param kwargs:
:return:
"""
# Checking if pk exists so that updates can be saved
if not RevenueWallet.objects.filter(pk=self.pk).exists() and RevenueWallet.objects.exists():
raise ValidationError('There can be only one instance of this model')
return super(RevenueWallet, self).save(*args, **kwargs)
When I try to create a class from within a parent class, such that the child class inherits 'self', I get the following error:
TypeError: Error when calling the metaclass bases
metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
class A(object):
create_proxy = False
def __init__(self, *args, **kwargs):
super(A, self).__init__(*args, **kwargs)
if self.create_proxy:
class Proxy(SomeMixin, self):
pass
[...]
I'm sure this is somehow possible; any suggestions?
Make the following change
...
if self.create_proxy:
class Proxy(SomeMixin, A): #use class name instead of self
pass
...
Also make sure that SomeMixin is a subclass of object, otherwise it will result it metaclass conflict.
class SomeMixin(object):
pass
class A(object):
create_proxy = True #False
def __init__(self, *args, **kwargs):
super(A, self).__init__(*args, **kwargs)
if self.create_proxy:
class Proxy(SomeMixin, A):
pass
a = A() #test
I have rather simple problem i guess. But i cant find a solution. It's been a while since i was writing in python/django...
My simple problem is, when im trying to add new Plain by admin interface.
TypeError: int() argument must be a string or a number, not 'Plain'
Site with form is rendering correctly, everything is fine till adding...
This is code of the models:
class Locomotion(models.Model):
transportation_firm_name = models.CharField(max_length=200)
transportation_number = models.CharField(max_length=200)
departure_date_time = models.DateTimeField()
arrival_date_time = models.DateTimeField()
class Meta:
abstract = True
def __str__(self):
return self.transportation_name
class Plain(Locomotion):
seat_number = models.CharField(max_length=200)
class_section = models.CharField(max_length=200)
def __init__(self, *args, **kwargs):
super(Locomotion, self).__init__(self, *args, **kwargs)
def __str__(self):
return "plain"
class Train(Locomotion):
seat_number = models.CharField(max_length=200)
section_numbers = models.CharField(max_length=200)
def __init__(self, *args, **kwargs):
super(Locomotion, self).__init__(self, *args, **kwargs)
And the same is happening when im trying to add Train or any other element of class extending Locomotion.
When you call super, you don't need to pass self:
super(Plain, self).__init__(*args, **kwargs)
Also, note that usually, you want to call super passing the class that you are calling it from, Plain in this case.
My Discount model describes common fields for all types of discounts in the system. I have some proxy models which describe concrete algorithm for culculating total. Base Discount class has a member field named type, which is a string identifing its type and its related class.
class Discount(models.Model):
TYPE_CHOICES = (
('V', 'Value'),
('P', 'Percentage'),
)
name = models.CharField(max_length=32)
code = models.CharField(max_length=32)
quantity = models.PositiveIntegerField()
value = models.DecimalField(max_digits=4, decimal_places=2)
type = models.CharField(max_length=1, choices=TYPE_CHOICES)
def __unicode__(self):
return self.name
def __init__(self, *args, **kwargs):
if self.type:
self.__class__ = getattr(sys.modules[__name__], self.type + 'Discount')
super(Discount, self).__init__(*args, **kwargs)
class ValueDiscount(Discount):
class Meta:
proxy = True
def total(self, total):
return total - self.value
But I keep getting exception of AttributeError saying self doesnt have type. How to fix this or is there another way to achieve this?
Your init method needs to look like this instead:
def __init__(self, *args, **kwargs):
super(Discount, self).__init__(*args, **kwargs)
if self.type:
self.__class__ = getattr(sys.modules[__name__], self.type + 'Discount')
You need to call super's __init__ before you will be able to access self.type.
Becareful with calling your field type since type is also a python built-in function, though you might not run into any problems.
See: http://docs.python.org/library/functions.html#type
call super(Discount, self).__init__(*args, **kwargs) before referencing self.type.