Hi I'm currently having trouble to skip not show error(admin side) when doing a query in Django signal function
I have these two model:
class TopUp(models.Model):
class Meta:
db_table = "topups"
verbose_name = 'Topup'
verbose_name_plural = 'Topups'
user = models.ForeignKey("backend.User", null=True, blank=True, related_name='user_optup', on_delete=models.CASCADE)
currency = models.ForeignKey("backend.Currency", null=True, blank=True, related_name='user_topup_currency', on_delete=models.SET_NULL)
TOPUP_METHOD_CHOICES = [
(0, 'fiat'),
(1, 'chain')
]
method = models.PositiveSmallIntegerField("Method", choices=TOPUP_METHOD_CHOICES, default=0)
amount = models.DecimalField("Amount", max_digits=65, decimal_places=0, default=0)
TOPUP_STATUS_CHOICES = [
(0, 'Pending'),
(1, 'Approved'),
(100, 'Rejected'),
]
status = models.PositiveSmallIntegerField("Status", choices=TOPUP_STATUS_CHOICES, default=0)
class UserBalance(models.Model):
class Meta:
db_table = "user_balances"
verbose_name = 'User Balance'
verbose_name_plural = 'User Balance'
user = models.ForeignKey("backend.User", null=True, blank=True, related_name='user_balance', on_delete=models.CASCADE)
currency = models.ForeignKey("backend.Currency", null=True, blank=True, related_name='user_balance_currency', on_delete=models.SET_NULL)
balance = models.DecimalField("Balance", max_digits=65, decimal_places=0, default=0)
The logic is on Django admin if status changed on TopUps(aka add money to account record) it will handle the balance on user balance If status changed to 1(Approved) then user balance with that currency got increased, if Reject then reverts and so on...
My admin.py:
class TopUpsAdmin(admin.ModelAdmin):
list_display = ('get_phone_number',)
def get_phone_number(self, obj):
return obj.user.phone_number
get_phone_number.short_description = 'User'
get_phone_number.admin_order_field = 'user_phone_number'
def get_readonly_fields(self, request, obj=None):
return ('id', )
def save_model(self, request, obj, form, change):
update_fields = []
# True if something changed in model
# Note that change is False at the very first time
if change:
if form.initial['status'] != form.cleaned_data['status']:
update_fields.append('status')
obj.save(update_fields=update_fields)
else:
obj.save()
else:
obj.save()
pass
admin.site.register(TopUp, TopUpsAdmin)
Here is my signal to handle when status changed on admin site(change view) of django:
@receiver(pre_save, sender=TopUp)
def handle_balance_on_topups_status_updated(sender, instance, update_fields, **kwargs):
if update_fields is not None:
if 'status' in update_fields:
try:
old_topups = TopUp.objects.get(pk=instance.id)
user = UserBalance.objects.get(user=instance.user, currency=instance.currency)
if (old_topups.status == 0) and (instance.status == 1):
user.balance += instance.amount
user.save()
elif (old_topups.status == 1) and (instance.status == 100) and (user.balance > 0):
user.balance -= instance.amount
user.save()
elif (old_topups.status == 1) and (instance.status == 0) and (user.balance > 0):
user.balance -= instance.amount
user.save()
elif (old_topups.status == 100) and (instance.status == 1):
user.balance += instance.amount
user.save()
except TopUp.DoesNotExist or UserBalance.DoesNotExist:
pass
I write a try-catch to not show error on the admin page if TopUp or UserBalane query fails in signal with a pass, but when I try to Approved on a TopUp
that has a currency that UserBalance doesn't have, my admin page still shows an error.
Traceback error:
Traceback (most recent call last):
web_1 | File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
web_1 | response = get_response(request)
web_1 | File "/usr/local/lib/python3.7/site-packages/django/core/handlers/base.py", line 115, in _get_response
web_1 | response = self.process_exception_by_middleware(e, request)
web_1 | File "/usr/local/lib/python3.7/site-packages/django/core/handlers/base.py", line 113, in _get_response
web_1 | response = wrapped_callback(request, *callback_args, **callback_kwargs)
web_1 | File "/usr/local/lib/python3.7/site-packages/django/contrib/admin/options.py", line 606, in wrapper
web_1 | return self.admin_site.admin_view(view)(*args, **kwargs)
web_1 | File "/usr/local/lib/python3.7/site-packages/django/utils/decorators.py", line 142, in _wrapped_view
web_1 | response = view_func(request, *args, **kwargs)
web_1 | File "/usr/local/lib/python3.7/site-packages/django/views/decorators/cache.py", line 44, in _wrapped_view_func
web_1 | response = view_func(request, *args, **kwargs)
web_1 | File "/usr/local/lib/python3.7/site-packages/django/contrib/admin/sites.py", line 223, in inner
web_1 | return view(request, *args, **kwargs)
web_1 | File "/usr/local/lib/python3.7/site-packages/django/contrib/admin/options.py", line 1648, in change_view
web_1 | return self.changeform_view(request, object_id, form_url, extra_context)
web_1 | File "/usr/local/lib/python3.7/site-packages/django/utils/decorators.py", line 45, in _wrapper
web_1 | return bound_method(*args, **kwargs)
web_1 | File "/usr/local/lib/python3.7/site-packages/django/utils/decorators.py", line 142, in _wrapped_view
web_1 | response = view_func(request, *args, **kwargs)
web_1 | File "/usr/local/lib/python3.7/site-packages/django/contrib/admin/options.py", line 1529, in changeform_view
web_1 | return self._changeform_view(request, object_id, form_url, extra_context)
web_1 | File "/usr/local/lib/python3.7/site-packages/django/contrib/admin/options.py", line 1572, in _changeform_view
web_1 | self.save_model(request, new_object, form, not add)
web_1 | File "/app/backend/admin.py", line 308, in save_model
web_1 | obj.save(update_fields=update_fields)
web_1 | File "/usr/local/lib/python3.7/site-packages/django/db/models/base.py", line 741, in save
web_1 | force_update=force_update, update_fields=update_fields)
web_1 | File "/usr/local/lib/python3.7/site-packages/django/db/models/base.py", line 766, in save_base
web_1 | update_fields=update_fields,
web_1 | File "/usr/local/lib/python3.7/site-packages/django/dispatch/dispatcher.py", line 175, in send
web_1 | for receiver in self._live_receivers(sender)
web_1 | File "/usr/local/lib/python3.7/site-packages/django/dispatch/dispatcher.py", line 175, in <listcomp>
web_1 | for receiver in self._live_receivers(sender)
web_1 | File "/app/backend/models.py", line 389, in handle_balance_on_topups_status_updated
web_1 | user = UserBalance.objects.get(user=instance.user, currency=instance.currency)
web_1 | File "/usr/local/lib/python3.7/site-packages/django/db/models/manager.py", line 82, in manager_method
web_1 | return getattr(self.get_queryset(), name)(*args, **kwargs)
web_1 | File "/usr/local/lib/python3.7/site-packages/django/db/models/query.py", line 408, in get
web_1 | self.model._meta.object_name
web_1 | backend.models.UserBalance.DoesNotExist: UserBalance matching query does not exist.
I expected it to not show an error but still save the changed status on admin page but user balance won't be affected (because the UserBalance with that currency doesn't exist)
Why my try-except isn't working in the signal ?
To catch multiple exception classes with one except
statement use parentheses to list exception classes:
except (TopUp.DoesNotExist, UserBalance.DoesNotExist):