Make sure attribute chains are evaluated safely

This commit is contained in:
Lukáš Kucharczyk 2024-05-30 11:15:52 +02:00
parent 51c25659a9
commit dc1a9d5c4f
Signed by: lukas
SSH Key Fingerprint: SHA256:vMuSwvwAvcT6htVAioMP7rzzwMQNi3roESyhv+nAxeg
2 changed files with 23 additions and 2 deletions

View File

@ -7,3 +7,23 @@ def safe_division(numerator: int | float, denominator: int | float) -> int | flo
return numerator / denominator return numerator / denominator
except ZeroDivisionError: except ZeroDivisionError:
return 0 return 0
def safe_getattr(obj, attr_chain, default=None):
"""
Safely get the nested attribute from an object.
Parameters:
obj (object): The object from which to retrieve the attribute.
attr_chain (str): The chain of attributes, separated by dots.
default: The default value to return if any attribute in the chain does not exist.
Returns:
The value of the nested attribute if it exists, otherwise the default value.
"""
attrs = attr_chain.split('.')
for attr in attrs:
try:
obj = getattr(obj, attr)
except AttributeError:
return default
return obj

View File

@ -1,5 +1,6 @@
from django import forms from django import forms
from django.urls import reverse from django.urls import reverse
from common.utils import safe_getattr
from games.models import Device, Edition, Game, Platform, Purchase, Session from games.models import Device, Edition, Game, Platform, Purchase, Session
@ -45,8 +46,8 @@ class EditionChoiceField(forms.ModelChoiceField):
class IncludePlatformSelect(forms.Select): class IncludePlatformSelect(forms.Select):
def create_option(self, name, value, *args, **kwargs): def create_option(self, name, value, *args, **kwargs):
option = super().create_option(name, value, *args, **kwargs) option = super().create_option(name, value, *args, **kwargs)
if value: if platform_id := safe_getattr(value, 'instance.platform.id'):
option["attrs"]["data-platform"] = value.instance.platform.id option["attrs"]["data-platform"] = platform_id
return option return option