Custom function in Django's model - python

I have model and i want to add my custom function, and when i create object this function call automatically.
this is my model and test function. it's only for testing
i want when i create Like object after call test function
class LikeManager(models.Manager):
def create(self, *args, **kwargs):
decrease = kwargs.pop("decrease")
new_like = self.model(**kwargs)
new_like.save(decrease=decrease)
return new_like
class Like(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name=_("user"))
question = models.ForeignKey(Question,on_delete=models.CASCADE,verbose_name=_("question"))
objects = LikeManager()
#this function (not printing)
#property
def test(self):
print("Testing")
return 1
def save(self, decrease, *args, **kwargs):
if not self.pk:
if decrease:
self.question.save()
else:
self.question.point += 1
self.question.save()
return super(Like, self).save(*args, **kwargs)
who can help me?

If you want to run the test function when a like object is created why don't you just put the test function inside of the save function?
class Like(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name=_("user"))
question = models.ForeignKey(Question,on_delete=models.CASCADE,verbose_name=_("question"))
objects = LikeManager()
def save(self, decrease, *args, **kwargs):
def test(self):
print("Testing")
return 1
if not self.pk:
if decrease:
self.question.save()
else:
self.question.point += 1
self.question.save()
return super(Like, self).save(*args, **kwargs)
Otherwise, you need to call the test function every time after you
create an object ( e.g.:
a = Like.objects.create(user=request.user,question=q)
a.test()
)

Related

Override save model Django save method with return

I have this function, I want to make it a method of a Message model class.
def save_message_to_db(message, message_id):
mex = Message(
message_id=message_id,
subject=message.subject,
sender=message.sender.address,
has_attachments=message.has_attachments,
sent_date=message.sent,
received_date=message.received
)
mex.save()
return mex
I've tried various ways, but still get errors. I need to return, expecially the id of the object saved.
Update
#staticmethod
def save_mex(message, message_id):
mex = Message(
message_id=message_id,
subject=message.subject,
sender=message.sender.address,
has_attachments=message.has_attachments,
sent_date=message.sent,
received_date=message.received
)
mex.save()
return mex
this is the only way I made it work, but this is a work around...
I get the errors in the Pyacharm IDE, I can not understand how to use the super() in this situation, because I want to pass an object and treat it in this method, not args and kwargs.
It should be as simple as this. Simply override the save method of your model and return the instance after the super call.
class YourModel(models.Model):
name = models.CharField(max_length=20)
def save(self, *args, **kwargs):
super(YourModel, self).save(*args, **kwargs)
return self
your_model_saved_instance = YourModel(name='Edoardo').save()
You can even make a base model class with this feature and use it in every model you want.
class BaseModel(models.Model):
class Meta:
abstract = True
def save(self, *args, **kwargs):
super(BaseModel, self).save(*args, **kwargs)
return self
class YourModel(BaseModel):
name = models.CharField(max_length=20)
your_model_saved_instance = YourModel(name='Edoardo').save()

is it possible to write if conditions inside models and if yes how?

this is my models and i am trying to assign category automatically if the user gets a marks greater than 10 he will get "legendary" category else "gold" category
class Intrest(models.Model):
user = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name="uuser")
marks=models.IntegerField(default=0)
choices = (
('Legendary', "Legendary"),
('Gold', "Gold"),
)
category=models.CharField(max_length=10,choices=choices,blank=True,null=True)
def value(self):
if self.marks==10:
self.category="Legendary"
else:
self.category="gold"
#property
def __str__(self):
return f"{self.user}"
I have made a value function but its not working can anyone tell me how can I achieve this?
Yes, it is possible: you need to use #property decorator:
#property
def category(self):
"""Returns category depending of mark."""
if self.marks==10:
self.category="Legendary"
else:
self.category="Gold"
You can override the model save() method:
class Intrest(models.Model):
...
def save(self, *args, **kwargs):
if self.marks > 10:
self.category = "Legendary"
else:
self.category = "Gold"
super().save(*args, **kwargs)

Django auto increment to custom field

I have Product db model, which should generate a code every time a new Product has been added.
class Product(models.Model): # Common
code = models.CharField(_("Product Code"), blank=True, max_length=100)
#... Other Fields
def __str__(self):
return self.code
def custom_seq(pk, letters=4, digits=3):
"""
Generates a sequence when letters=4, digits=3 then, 'AAAA000', 'AAAA001', ..., 'ZZZZ999'
Generates a sequence when letters=3, digits=4 then, 'AAA0000', 'AAA0001',..., 'ZZZ9999'
"""
alpha_list = [string.ascii_uppercase]*letters
digit_list = [string.digits]*digits
for i in itertools.product(*alpha_list):
for j in itertools.product(*digit_list):
yield "".join(i + j)
def save(self, *args, **kwargs):
product_code = next(self.custom_seq())
print("Code", product_code) #-- prints `AAAA000`
if not self.code:
self.code = product_code
return super(Product, self).save(*args, **kwargs)
Everytime, I save a new product its generating only first sequence of my custom_seq() ie. AAAA000. but it should add new code to each newly generated instance such as 'AAAA001', 'AAAA002', 'AAAA003'...
You are instantiating custom_seq generator each time you'are creating a new instance.
Put your custom_seq(pk, letters=4, digits=3) method somewhere outside your Product model (I would recommend you to put separately in Utility module) and instantiate it globally.
Finally, use it inside your save method.
seq = custom_seq()
class Product(models.Model): # Common
code = models.CharField(_("Product Code"), blank=True, max_length=100)
#... Other Fields
#... Other methods
def save(self, *args, **kwargs):
if not self.code:
self.code = next(seq)
return super(Product, self).save(*args, **kwargs)

Django passing arguments through save methods (models)

i have models in django like this:
class Client(models.Model):
type = (choices)
class Bill(models.Model):
client = models.ForeignKey(Client)
class Detail(models.Model):
total = models.MoneyField() # i used currency package
bill = models.ForeignKey(Bill)
Detail class contains sales detail for the Bill, i already made a transaction to save bill and details at the same time in Bill.save() method but i want to pass Client.type from Bill.save() to Detail.Save(), i want something like that
def save(self, *args, **kwargs): #this is Bill save method
client = self.Client
transaction.atomic:
super(Bill, self).save(*args, **kwargs)
for detail in self.details
detail.save(client)
def save(self, *args, **kwargs): #this is Detail save method
self.pricing(client)
super(Detail, self).save(*args, **kwargs)
def pricing(self, client):
if client.type = 'value1':
self.total = self.total - (self.total*5/100)
elif client.type = 'value2':
self.total = self.total - (self.total*7/100)
else:
self.total = self.total - (self.total*10/100)
i don't know how passing arguments works on python and Django, what is the cleanest solution to solve this problem? in short i want the bill.save method to pick the client.type value and passe it through detail.save to calculate total with cases.
Thanks
You can pass the parameter in kwargs in save method try the following code to pass the client variable (detail.save(client=client)) in another save method and access this variable by using client = kwargs.get('client')
def save(self, *args, **kwargs): #this is Bill save method
client = self.Client
transaction.atomic:
super(Bill, self).save(*args, **kwargs)
for detail in self.details
detail.save(client=client)
def save(self, *args, **kwargs): #this is Detail save method
client = kwargs.get('client')
self.pricing(client)
super(Detail, self).save(*args, **kwargs)
May be this helps you..
In your case, you can simple use self property:
def save(self, *args, **kwargs): #this is Detail save method
self.pricing(self.bill.client)
# ^^^^^^^^^^^
super(Detail, self).save(*args, **kwargs)

Extra parameter for Django models

With Django models, I want to achieve this:
class Foo(models.Model):
name = models.CharField(max_length=50)
#wrapping the save function, including extra tasks
def save(self, *args, **kwargs):
super(Foo, self).save(*args, **kwargs)
if extra_param:
...do task 1
else:
...do task 2
And while crating Foo I want to pass such as
Foo(name="Bill Gates",extra_param=True).save() # now triggers the task 1
Foo(name="Bill Gates").save() # now triggers the task 2
How can this be done? I am also open to any other suggestions :)
Thanks
You can define non-persistent fields in your model.
class Foo(models.Model):
name = models.CharField(max_length=50)
extra_param = False
def save(self, *args, **kwargs):
...
print self.extra_param
Alternatively, you can do:
Foo(name="Bill Gates").save(extra_param=True)
def save(self, *args, **kwargs):
...
print kwargs["extra_param"]

Categories