AI Briefing
KO

How to correctly pass arguments to a transaction.on_commit callback in a for loop

·2020.10.26 12:00

Key point

In a for loop, on_commit callbacks must fix the current value using a lambda default argument.

Details

When using transaction.on_commit() together with a for loop inside transaction.atomic(), you need to be careful about when the variable passed to the callback is evaluated.

For example, if you want to send a post-commit notification to 10 winners of a raffle event, you need to register a callback for each loop iteration. However, if you write it like lambda send_notification(user), only the last user value after the loop ends is referenced, which can cause the same user to receive the notification repeatedly.

The core cause is that the callback fails to fix the current value at the time of registration, rather than at the time it is executed. Since on_commit() executes a function that takes no arguments, it re-reads the outer variable user at runtime, and by that point all callbacks see the same last value.

The solution is to bind the current value using the default value of the anonymous function's parameter.

  • Wrong example: transaction.on_commit(lambda send_notification(user))
  • Wrong example: transaction.on_commit(lambda user: send_notification(user))
  • Correct example: transaction.on_commit(lambda user=user: send_notification(user))

This way, user is stored as the default value at each iteration of the loop, so when the callback executes after commit, each winner receives their own individual notification.

This summary was generated automatically by AI. Check the original for the author's claims and context. Copyright belongs to the original author.

Our guide explains how the AI works. Report summary errors, attribution issues, or removal requests via Contact.