Coverage for audoma/django/db/fields.py: 37%

1"""Audoma Django model Fields

2 This module contains all the fields from Django models with additional functionality.

3 By inheriting from Audoma Mixins, an example is generated for each field (i.e. FloatField will have

4 example generated based on field's min and max values).

5 We can define custom example by simply passing `example` as an argument to the field.

6"""

7

8 import random

9 import sys

10

11 import phonenumbers

12 from djmoney.models import fields as djmoney_fields

13 from djmoney.utils import get_currency_field_name

14 from macaddress.fields import MACAddressField

15 from phonenumber_field.modelfields import PhoneNumberField

16 from phonenumber_field.phonenumber import to_python

17

18 from django.db import models

19 from django.db.models.fields import ( # noqa: F401

20 BLANK_CHOICE_DASH,

21 NOT_PROVIDED,

22 __all__,

23)

24

25 from audoma.django import forms

26 from audoma.example_generators import generate_lorem_ipsum

27 from audoma.mixins import ModelExampleMixin

28

29

30 try:

31 from django.db.models import JSONField

32 except ImportError:

33 try:

34 from jsonfield import JSONField

35 except ImportError as err:

36 raise ImportError(

37 "You are using old version of Django that doesn't support JSONField. Please install django-jsonfield"

38 ) from err

39

40

41 this = sys.modules[__name__]

42

43

44 for field_name in __all__:

45 if field_name in ["BLANK_CHOICE_DASH", "NOT_PROVIDED"]:

46 continue

47

48 setattr(

49 this,

50 field_name,

51 type(field_name, (ModelExampleMixin, getattr(models, field_name)), {}),

52 )

53

54

55 __all__.extend(["MoneyField", "CurrencyField", "PhoneNumberField", "MACAddressField"])

56

57

58 class CurrencyField(ModelExampleMixin, djmoney_fields.CurrencyField):

59 def __init__(self, *args, **kwargs) -> None:

60 default = kwargs.get("default", None)

61 if default and str(default) != "XYZ":

62 self.example = default

63 elif kwargs.get("choices", None):

64 self.example = random.choice(kwargs["choices"])[0]

65 else:

66 self.example = "XYZ"

67 super().__init__(*args, **kwargs)

68

69

70 class MoneyField(ModelExampleMixin, djmoney_fields.MoneyField):

71 def add_currency_field(self, cls, name):

72 """

73 Adds CurrencyField instance to a model class and creates example in documentation.

74 """

75

76 currency_field = CurrencyField(

77 price_field=self,

78 max_length=self.currency_max_length,

79 default=self.default_currency,

80 choices=self.currency_choices,

81 null=self.default_currency is None,

82 )

83 currency_field.creation_counter = self.creation_counter - 1

84 currency_field_name = get_currency_field_name(name, self)

85 cls.add_to_class(currency_field_name, currency_field)

86 self._currency_field = currency_field

87

88 def formfield(self, **kwargs):

89 defaults = {

90 "form_class": forms.MoneyField,

91 "decimal_places": self.decimal_places,

92 }

93 defaults.update(kwargs)

94 if self._has_default:

95 defaults["default_amount"] = self.default.amount

96 return super(djmoney_fields.MoneyField, self).formfield(**defaults)

97

98

99 class PhoneNumberField(ModelExampleMixin, PhoneNumberField):

100 def __init__(self, *args, region=None, **kwargs) -> None:

101 super().__init__(*args, region=region, **kwargs)

102 if not kwargs.get("example", None):

103 number = phonenumbers.example_number(region)

104 self.example = str(to_python(number))

105

106

107 class CharField(ModelExampleMixin, models.CharField):

108 def __init__(self, *args, **kwargs) -> None:

109 super().__init__(*args, **kwargs)

110 max_length = kwargs.get("max_length", 80)

111 if not kwargs.get("example", None) and max_length:

112 self.example = generate_lorem_ipsum(max_length=max_length)

113

114

115 class TextField(ModelExampleMixin, models.TextField):

116 def __init__(self, *args, **kwargs) -> None:

117 super().__init__(*args, **kwargs)

118 if not kwargs.get("example", None):

119 self.example = generate_lorem_ipsum()

120

121

122 class MACAddressField(ModelExampleMixin, MACAddressField):

123 pass

124

125

126 class JSONField(ModelExampleMixin, JSONField):

127 pass

128

129

130 if "JSONField" not in __all__:

131 __all__.append("JSONField")