Reputation: 2939
I'm trying to override a save method so that on creation of one model, an instance of the second model is created. However, it looks like the secondary model that I'm trying to create (Restaurant
in this example) is being created twice. Why is that?
models.py
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
def __str__(self):
return "%s the place" % self.name
def save(self, *args, **kwargs):
super(Place, self).save(*args, **kwargs)
if Restaurant.objects.filter(place=self).count() == 0:
restaurant = Restaurant.objects.create(place=self)
class Restaurant(models.Model):
place = models.OneToOneField(
Place,
on_delete=models.CASCADE,
primary_key=True,
)
Upvotes: 1
Views: 2927
Reputation: 1
You can try:
obj.save(commit=False)
#change fields
obj.save()
First you will create save 'instance', do what you have to do, and then call the right save()
method.
Upvotes: 0
Reputation: 53734
Your save method does not have proper indentation. I assume this was an error in cut and paste. With in that method.
if Restaurant.objects.filter(place=self).count() == 0:
restaurant = Restaurant.objects.create(restaurant=self)
This is essentially what get_or_create does but does atomically.
This method is atomic assuming correct usage, correct database configuration, and correct behavior of the underlying database. However, if uniqueness is not enforced at the database level for the kwargs used in a get_or_create call (see unique or unique_together), this method is prone to a race-condition which can result in multiple rows with the same parameters being inserted simultaneously.
You can do the same in your own code of course with an atomic block but why bother. Just do
Restaurent.objects.get_or_create(place=self)
and isn't that place=self
instead of restaurent=self
as in your save method?
Upvotes: 1