Add needs_price_update field to Purchase model #94
Reference in New Issue
Block a user
Delete Branch "purchase-needs-price-update"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Resolves #92
Replace fragile price change detection in Purchase.save() with a lazy dirty flag approach. A pre_save/post_save signal pair detects price/currency changes without extra DB queries, and convert_prices() uses the flag to determine which purchases need conversion.
Changes
needs_price_updateBooleanField with db_indexprice_or_currency_differ_from()methodconvert_prices()to filter on needs_price_update flag_get_exchange_rate()and_save_converted_price()helpersSolid PR. The signal-based dirty flag pattern is a common Django idiom for this kind of problem. No blocking concerns — ready to approve and merge.
Here are a few observations:
1.
games/signals.pyThe signal approach adds an extra DB query per update (to fetch the old instance). The old code also fetched from DB in
save(), so it's a wash query-wise. Worth noting it's a trade-off, not strictly fewer queries.2.
games/migrations/0016_add_needs_price_update.pyThe raw SQL
UPDATEin the migration backfill could lock the table on large datasets. Consider chunked updates if the table grows significantly.3.
games/tasks.py_get_exchange_rate()returns a bare float (not anExchangeRateobject), but the variableexchange_rateis misleading. Consider renaming torate.4.
games/tests.pyoverride_settings(CACHES=...)intest_convert_prices_sets_flag_to_falseseems unnecessary sinceconvert_prices()doesn't use caching. Could be removed if left from an earlier version.5. Log level in
games/tasks.pyExchange rate lookups use
logger.info(). Considerlogger.debug()for these routine operations and keepinfofor noteworthy events (success, failure).Inline comments on the diff.
The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.
This signal handler fetches the old instance from the DB on every update. The old code in
save()also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off._get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to
rate.Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
Inline comments on the diff.
The raw SQL UPDATE in this migration could lock the table on large datasets. Consider chunked updates if the table grows significantly.
This signal handler fetches the old instance from the DB on every update. The old code in
save()also fetched from DB, so it's a wash query-wise — not strictly fewer queries. Just worth noting the trade-off._get_exchange_rate() returns a bare float (not an ExchangeRate object), but the variable name is misleading. Consider renaming to
rate.Exchange rate lookups use logger.info() — consider logger.debug() for these routine operations.
override_settings(CACHES=...) seems unnecessary since convert_prices() doesn't use caching. Could be removed if left from an earlier version.
Done. Three changes applied:
tasks.py:
tests.py: