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)
Related
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()
)
I've got a Django models:
class Item_received_log(models.Model):
name = models.CharField(max_length=250)
quantity = models.FloatField(default=1)
class Inventory (models.Model):
name = models.CharField(max_length=250)
quantity = models.FloatField(default=1)
I would like to update Inventory.quantity each time new item to Item_received_log is posted with matching name. I am not sure if it is right but I've decided to override save method of Item_received_log class so it updates Inventory list upon saving:
def save(self, *args, **kwargs):
obj, created = Inventory.objects.update_or_create(
name=self.name,
defaults = {'quantity':(quantity + self.quantity)})
super(Item_received_log, self).save(*args, **kwargs)
And in returns:
NameError at /admin/accountable_persons/item_received_log/17/change/
global name 'quantity' is not defined
How can I resolve my issue or come up with better solution?
Would have been a lot easier if we could simply throw in an F() expression into the default part of update_or_create to do all the magic, but the issue requesting this feature is still open.
You can, however, use a more verbose approach for now:
from django.db.models import F
def save(self, *args, **kwargs):
obj, created = Inventory.objects.get_or_create(name=self.name)
obj.quantity = F('quantity') + self.quantity
obj.save()
super(Item_received_log, self).save(*args, **kwargs)
I am trying to override the save method on a model in order to generate a unique, second auto-incrementing id.
I create my class and override the save() method, but for some reason it is erroring out with the following error:
TypeError: %d format: a number is required, not NoneType
Here's the code:
class Person(models.Model):
target = models.OneToOneField(Target)
person = models.OneToOneField(User)
gender = models.CharField(max_length=1)
gender_name = models.CharField(max_length=100)
person_id = models.CharField(max_length=100)
def save(self, *args, **kwargs):
self.person_id = "%07d" % self.id
super(Person, self).save(*args, **kwargs)
Is it because I didn't pass an id parameter and it hasn't saved yet? Is there anyway to generate a value from the id?
Safest and easiest way to achieve what you want is to use a post_save signal because it is fired right after save is called, but before the transaction is committed to the database.
from django.dispatch import receiver
from django.db.models.signals import post_save
#receiver(post_save, sender=Person)
def set_person_id(sender, instance, created, **kwargs):
if created:
instance.person_id = "%07d" % instance.id
instance.save()
Yes, self.id will be Nonein some cases, and then the assignment will fail.
However you cannot just the assignment and the call to super, as suggested in the comments, because then you wouldn't be persisting the assignment to the database layer.
You need to check whether the model has an id and then proceed differently:
def save(self, *args, **kwargs):
if not self.id: # Upon instance creation
super(Person, self).save(*args, **kwargs) # Acquire an ID
self.person_id = "%07d" % self.id # Set the person_id
return super(Person, self).save(*args, **kwargs)
This issues two save operations to the database. You will want to wrap them in a transaction to make sure your database receives these two fields simultaneously.
from django.db import IntegrityError, transaction
class Person(models.Model):
target = models.OneToOneField(Target)
person = models.OneToOneField(User)
gender = models.CharField(max_length=1)
gender_name = models.CharField(max_length=100)
person_id = models.CharField(max_length=100)
def create_person_id(self):
if not self.id: # Upon instance creation
super(Person, self).save(*args, **kwargs) # Acquire an ID
self.person_id = "%07d" % self.id
def save(self, *args, **kwargs):
try:
with transaction.atomic():
self.create_person_id
return super(Person, self).save(*args,**kwargs)
except IntegrityError:
raise # or deal with the error
I agree that signals might be the better option, if not, try using pk instead of id.
class Person(models.Model):
# [ . . . ]
def save(self, *args, **kwargs):
self.person_id = "%07d" % self.pk
super(Person, self).save(*args, **kwargs)
I want to input something like(via the admin page):
text = 't(es)t'
and save them as:
'test'
on database.
And I use this Regex to modify them:
re.sub(r'(.*)\({1}(.*)\){1}(.*)', r'\1\2\3', text)
I know how to transform text from 't(es)t' to 'test' but the problem is
when i use
name = models.CharField(primary_key=True, max_length=16)
to input text(from admin). It immediately save to database cannot modify it before saving.
Finally, From a single input from admin text = 't(es)t' (CharField).
What do i want?
To use 't(es)t' as a string variable.
Save 'test' to database
Try to overide the save method in your model,
class Model(model.Model):
name = models.CharField(primary_key=True, max_length=16)
# This should touch before saving
def save(self, *args, **kwargs):
self.name = re.sub(r'(.*)\({1}(.*)\){1}(.*)', r'\1\2\3', self.name)
super(Model, self).save(*args, **kwargs)
Update:
class Model(model.Model):
name = models.CharField(primary_key=True, max_length=16)
name_org = models.CharField(max_length=16)
# This should touch before saving
def save(self, *args, **kwargs):
self.name = re.sub(r'(.*)\({1}(.*)\){1}(.*)', r'\1\2\3', self.name)
self.name_org = self.name # original "t(es)t"
super(Model, self).save(*args, **kwargs)
I need some help with an issue.
I have three models, Reference, Relation ans Circuit. Relation is an inline of the first one. Circuit and Relation are related. What I have to do is:
- I'm in Reference 1 and I have selected some Circuits inside my Relation1 to RelationN.
- When I save, I need to save Relation1 to RelationN, and other RelationFirst (created when the Reference model is saved) who must contain all the Circuits that exist in the other Relations of that Reference.
The code that I have right now, who doesn't do it, is:
class Reference(models.Model):
title = models.CharField(max_length=200, verbose_name = _('title'))
def __unicode__(self):
return u"\n %s" %(self.title)
def save(self, force_insert=False, force_update=False, *args, **kwargs):
is_new = self.id is None
super(Reference, self).save(force_insert, force_update, *args, **kwargs)
if is_new:
Relation.objects.create(reference=self, first = True)
relation = Relation.objects.get(reference=self, first = True)
circuit = Circuit.objects.get(name = '0')
relation.circuit.add(circuit)
class Relation(models.Model):
first = models.BooleanField()
reference = models.ForeignKey(Reference)
circuit = models.ManyToManyField('Circuit', verbose_name = _('Circuits'), null=True, blank=True, related_name = 'relation_circuit')
def __unicode__(self):
return u"%s" %(self.reference)
def save(self, force_insert=False, force_update=False, *args, **kwargs):
relation1 = Relation.objects.get(reference=self.reference, first = True)
super(Relation, self).save(force_insert, force_update, *args, **kwargs)
for circ in self.circuits:
circuit = Circuit.objects.get(pk = circ)
relation1.circuit.add(circuit)
Any help? Because I can't iterate the ManyToManyRelatedField, and I don't know how to do it. Thank you very much!
You should do it that way:
for circ in self.circuit.all():