Signals getting executed twice?

So, I have a post_save signal using the @receiver decorator. It “looks” like it’s getting called twice. I don’t see where I could be committing the data twice.

I’m using the signal to make an “Activity Log”. In this case, it’s my model “Batch” and “addBatch()” view.

models.py (snipped):

class Batch(models.Model):

    def __str__(self):
        return self.name

    class Meta:
        verbose_name_plural = 'batches'

    name = models.CharField(max_length=50)
    startdate = models.DateTimeField(auto_now=True)
    enddate = models.DateTimeField(null=True, blank=True)
    lotId = models.CharField(max_length=7, null=True) # Bottledate L[2digityear][0paddedYearDays] = L22088
    #size = models.IntegerField()
    #size_units = models.ForeignKey(Unit, on_delete=models.SET("_del"))
    size = DescriptiveQuantityField(base_units='liters', unit_choices=['liters','gallons'])
    active = models.BooleanField(default=True)
    # Using the 'related_name' on batches, applies that name on the other side for "Fermenter.batch"
    #fermenter = models.ManyToManyField(Fermenter, blank=True, related_name='batch')
    fermenter = models.ForeignKey(Fermenter, on_delete=models.RESTRICT)
    startingGravity = QuantityField(base_units="sg")
    estimatedEndGravity = QuantityField(base_units="sg")
    #category = models.ForeignKey(BatchCategory, on_delete=models.SET("_del"), blank=True, null=True)
    category = models.ForeignKey(BatchCategory, on_delete=models.RESTRICT, blank=True, null=True)
    #activity = models.ManyToManyField(ActivityLog, blank=True, related_name='batch')
    activity = models.ManyToManyField(ActivityLog, blank=True, related_name='batch')
    #recipe = models.ForeignKey(Recipe, on_delete=models.SET("_del"), null=True, blank=True)
    recipe = models.ForeignKey(Recipe, on_delete=models.RESTRICT, null=True, blank=True)
    # TODO Add additional objects
    aging_vessel = None
    packaging = None

    def transfer(self,src_vessel, dst_vessel):
        pass

    def complete(self):
        self.enddate = datetime.now()
        self.active = False

    def current_gravity(self):
        gravity_tests = self.tests.filter(type__shortid='specific-gravity')
        if len(gravity_tests) > 1:
            return gravity_tests.last().value
        return gravity_tests[0].value


    def percent_complete(self):
        est_fg = self.estimatedEndGravity.magnitude
        current_gravity = self.current_gravity()
        return round((self.startingGravity.magnitude - current_gravity) / (self.startingGravity.magnitude - est_fg) * 100)

# If a batch is saved with a Starting Gravity, add that test
@receiver(post_save,sender=Batch)
def addGravityTest(sender,instance,**kwargs):
    print("Adding Gravity")
    if instance.startingGravity:
        gravTest = BatchTest()
        testType = BatchTestType.objects.filter(shortid='specific-gravity')[0]
        gravTest.type = testType
        gravTest.value = instance.startingGravity
        gravTest.description = "Auto created from new batch."
        gravTest.datetime = datetime.now()
        unit = Unit.objects.filter(name__contains="specific")[0]
        gravTest.units = unit
        gravTest.batch = instance
        print("Saving gravity")
        gravTest.save()

@receiver(post_save,sender=BatchNote)
@receiver(post_save,sender=BatchAddition)
@receiver(post_save,sender=BatchTest)
@receiver(post_save,sender=Batch)
def addActivity(sender,instance,created=False,**kwargs):
    text = None
    batch = None
    date = datetime.now()
    if sender.__name__ == "Batch":
        batch = instance
        if created:
            text = "Batch Created"
        else:
            text = "Batch Modified"
    if sender.__name__ == "BatchNote":
        batch = instance.batch
        if created:
            text = "Added ["+instance.notetype.name+"] :: " + instance.text
    if sender.__name__ == "BatchAddition":
        batch = instance.batch
        if created:
            text = "Added [" + instance.name.name + "] :: " + str(instance.amount) + " " + instance.units.name
        else:
            text = "Updated [" + instance.name.name + "]"
    if sender.__name__ == "BatchTest":
        batch = instance.batch
        if created:
            text = "Added [" + instance.type.name + "] :: " + str(instance.value) + " " + instance.units.name
        else:
            text = "Updated [" + instance.type.name + "]"
    if text:
        log = ActivityLog(datetime=date,text=text)
        log.save()
        batch.activity.add(log)

views.py (snipped):

def addBatch(request, pk=None):
    if request.method == "POST":
        form = BatchAddForm(request.POST)
        if form.is_valid():

            batch = Batch()
            batch.name = form.cleaned_data['name']
            batch.startdate = form.cleaned_data['startdate']
            batch.size = form.cleaned_data['size']
            #size_unit = Unit.objects.filter(pk=form.cleaned_data['size_units'])[0]
            #batch.size_units = size_unit
            batch.startingGravity = form.cleaned_data['startingGravity']
            batch.estimatedEndGravity = form.cleaned_data['estimatedEndGravity']
            batch.fermenter = form.cleaned_data['fermenter']
            newbatch = batch.save()
            #fermenters = form.cleaned_data['fermenter']
            batch.recipe = form.cleaned_data['recipe']
            #for fermenter in fermenters:
            #    batch.fermenter.add(fermenter)
            batch.save()
            return HttpResponseRedirect(reverse('batch', kwargs={'pk': batch.pk}))
        else:
            return render(request, template_name='batchthis/addBatch.html', context={'form': form})
    else:
        if pk:
            batch = Batch.objects.get(pk=pk)
            form = BatchAddForm(initial=model_to_dict(batch))
            form.fermenter = batch.fermenter
        else:
            form = BatchAddForm()
            form.fields['fermenter'].queryset = Fermenter.objects.filter(vessel__status=Vessel.STATUS_READY)
        return render(request, "batchthis/addBatch.html", {'form': form})

Activity Log:

2025-02-22 18:47 PM: Added [Specific Gravity] :: 1.108 Specific Gravity
2025-02-22 18:47 PM: Batch Created
2025-02-22 18:47 PM: Added [Specific Gravity] :: 1.108 Specific Gravity
2025-02-22 18:47 PM: Batch Modified

I’m a little confused. Anyone have thoughts?

Ok. I didn’t see it before in my IDE with all the files, but now that I’m seeing everything in a single page, it’s obvious my post_save signal to add the Gravity Test causes the “Modified” after “Created”. So, that’s explainable.

But, why have the duplicate “Added [Specific Gravity]”? I’ll have to go back through my code again. Sorry folks. Sometimes we solve our own questions just by posting here.

1 Like