If you need to modify instance fields depending on the instance’s pk or id, hop on.
When you create an instance, before it is saved, you can’t have pk or id as it is not yet created.
def save(self, *args, **kwargs):
# self.pk == None
# self.id == None
super().save(*args, **kwargs)
# self.pk != None
# self.id != None
If you have a property that somehow depends on the value of self.pk or self.id and you want to have it saved on creating, you have two options.
Make it a @property
If you don’t really need it for MyModel.objects.filter() or MyModel.objects.get() purposes, then just make it a @property and chill:
@property
def something_coded(self):
return 'something_' + str(self.pk)
Make it a field
Make a models.CharField or whatever you want and modify the save method:
def save(self, *args, **kwargs):
# self.pk == None
# self.id == None
super().save(*args, **kwargs)
# self.pk != None
# self.id != None
if not self.something_coded:
obj = MyModel.objects.get(pk=self.pk)
obj.something_coded = 'something_' + str(self.pk)
obj.save()
This way it will only work once – if your field something_coded is empty (just when you create it).
The only problem with this is that when you create an instance like that somewhere in your code (say, in views or in a @classmethod) it works like this:
new_instance = MyModel.objects.create()
print(new_instance.something_coded)
>> null
So if you want to access something_coded field immediately, do this instead:
pk = MyModel.objects.create()
new_instance = MyModel.objects.get(pk=pk)
print(new_instance.something_coded)
>> 'something_5'
I am yet to test if it works with ManyToManyField (without through table).