Tengo dos modelos que usarán el mismo CardNumberField() para almacenar números de tarjetas de crédito. ¿Cómo puedo agregar un método personalizado al campo para enmascarar los números de tarjeta?
He creado CardNumberField() que hereda de models.Charfield :
# CARD NUMBER FIELD class CardNumberField(models.CharField): description = _('card number') def __init__(self, *args, **kwargs): kwargs['max_length'] = 19 super().__init__(*args, **kwargs) CardNumberField() se importa y se usa en mi clients/models.py :
# CARD MODEL class Card(models.Model): number = CardNumberField() ... def __str__(self): return 'Card [{number}]'.format(number=self.number)... y en mis transacciones/modelos.py :
# TRANSACTION MODEL class Transaction(models.Model): card_number = CardNumberField() ... def __str__(self): return 'Transaction ...' Entonces, ¿cómo puedo agregar el siguiente método a mi CardNumberField() para que lo usen mis dos modelos?
def masked_number(self): # display masked card number number = self.number return number[-4:].rjust(len(number), '#')Además, ¿cómo tomaré este método de campo en una clase de serializador DRF?
Puede anular el método contribute_to_class no solo para contribuir con el campo, sino también para incluir un método adicional:
from functools import partialmethod def _mask_number(self, field): number = getattr(self, field.attname) return number[-4:].rjust(len(number), '#') # CARD NUMBER FIELD class CardNumberField(models.CharField): description = _('card number') def __init__(self, *args, **kwargs): kwargs['max_length'] = 19 super().__init__(*args, **kwargs) def contribute_to_class (self, cls, name, **kwargs): super().contribute_to_class(cls, name, **kwargs) setattr( cls, f'masked_{self.name}', partialmethod(_mask_number, field=self) ) Si agrega un campo foo a una clase modelo, automáticamente agregará un método masked_ foo a esa clase. Esto también significa que si tiene dos o más CardNumberField s, agregará dos o más métodos masked_ foo .
Utilice un modelo abstracto en su lugar:
class ModelWithCardNumber(models.Model): card_number = models.CharField(max_length=19) @property def masked_number(self): return self.card_number[-4:].rjust(len(number), '#') class Meta: abstract = True class Card(ModelWithCardNumber): def __str__(self): return 'Card [{number}]'.format(number=self.number) class Transaction(ModelWithCardNumber): def __str__(self): return 'Transaction ...' Ahora en su serializador puede acceder a Card.masked_number y Transaction.masked_number .