user3214546
user3214546

Reputation: 6831

How can I avoid recursion during saving of django model

I have a model Entry

Now whenever Entry is created for any date. Then before saving I need to make check and add more entries, for example e.g.

Entry 1 - red

Now suppose if any entry.color = red Then I also need to make two more entries like

Entry 2 - red2
Entry 3 - red3

Now I have put this in pre_save signal

@receiver(pre_save, sender=Entry)
def new_entries(sender, instance, *args, **kwargs):
     pass

Now my problem is this ends in infinite recursion as those new entries which I want to save also send pre_save signal and this loop never finishes.

Where do put this logic so that recursion does not occur?

Upvotes: 3

Views: 1849

Answers (4)

Tejsingh
Tejsingh

Reputation: 297

In post_save singal in django for avoiding recursion 'if created' check is required

from django.dispatch import receiver
from django.db.models.signals import post_save
@receiver(post_save, sender=DemoModel)
def _post_save_receiver(sender,instance,created, **kwargs):
if created:            
    print('hi..')
    instance.save()

Upvotes: 0

Sebastian Wozny
Sebastian Wozny

Reputation: 17506

I would solve it with an additional argument to save, as opposed to attaching to pre_save:

import django.db.models
class Entry(models.Model):
    color=models.CharField(max_length="50")
    def save(self,create_children=True,**kwargs):
        if create_children and not self.pk:
            result = super(Entry,self).save(**kwargs)
            Entry(color=self.color).save(create_children=False)
            Entry(color=self.color).save(create_children=False)
        else:
            result = super(Entry,self).save(**kwargs)
        return result

You want to make sure you call super(Entry,self).save(**kwargs) before you actually construct the children, otherwise you will clutter the database with models when super() raises an IntegrityError

Upvotes: 4

Jorick Spitzen
Jorick Spitzen

Reputation: 1639

I think you should have 2 separate models for this. Your 'parent' Entry could be a subclass of the main Entry model so that only IT creates new child Entries.

class Entry(models.Model):
    pass
    # whatever you need here

class ParentEntry(Entry):

    @receiver(pre_save, sender=ParentEntry)
    def new_entries(sender, instance, *args, **kwargs):
        pass

The reason for adding another model is that these models actually do 2 different things, 1 creates more when creating, 1 does not. For clarity, I would prevent situations where 1 model's constructor can do 2 separate things.

Upvotes: 0

scytale
scytale

Reputation: 12641

something like this should work:

class Entry(model.Model):

   def save(self, color, create_more=True, *args, **kwargs):
       if self.pk is None:  # this is a new Entry              
           if create_more:
               new_color = '%s2' % color
               Entry(color=new_color, create_more=False).save()

       super(Entry, self).save(...)

tho I suspect there is a better way, but I can't say without knowing more details of what you are trying to do.

Upvotes: 0

Related Questions