I have the following function that is called via signal. 1) check if incluencer exists. 2) Increase discount by +1. Currently, I hit the database twice. Is there a better way to write that? Additionally, I wonder I can check 2) all on a database level so I don't need the for-loop.
@receiver(signal=charge_succeeded)
@transaction.atomic
def create_influencer_transaction(sender, order, charge, **kwargs):
order_exists = Transaction.objects.filter(order=order).exists()
if order_exists:
return None
# 1) Check if influencer exists
first_order_item = order.order_items.first()
influencer = first_order_item.social_referral
if not influencer:
return None
total_points_earned = order.order_items.aggregate(
total=Sum(
F('unit_points_earned') * F('quantity'),
output_field=IntegerField()
)
)['total'] or 0
Transaction.objects.create(
[...]
)
# 2) Redeemed amount + 1
for order_item in order.order_items.all():
social_discount = order_item.social_discount
if social_discount:
social_discount.redeemed_amount = F('redeemed_amount') + 1
social_discount.save(update_fields=['redeemed_amount'])
break
models.py
class OrderItem(AbstractItem, AbstractDiscountItem, AbstractSocialItem):
order = models.ForeignKey(
[...]
)
social_discount = models.ForeignKey(
'discounts.SocialDiscount',
on_delete=models.PROTECT,
related_name='order_items',
null=True,
blank=True,
) # PROTECT = don't allow to delete the discount if an order_item exists
class SocialDiscount(AbstractDiscount):
event = models.OneToOneField(
[...]
) # CASCADE = delete the discount if the event is deleted
tickets = models.ManyToManyField(
[...]
)
ForeignKey. Many order_items can have the samesocialdiscount\$\endgroup\$redeemed_amountis anIntegerField? \$\endgroup\$