def _expand_money_args(model, args): """ Augments args so that they contain _currency lookups - ie.. Q() | Q() """ for arg in args: if isinstance(arg, Q): for i, child in enumerate(arg.children): if isinstance(child, Q): _expand_money_args(model, [child]) elif isinstance(child, (list, tuple)): name, value = child if isinstance(value, Money): clean_name = _get_clean_name(name) arg.children[i] = Q(*[ child, (get_currency_field_name(clean_name), smart_unicode(value.currency)) ]) if isinstance(value, BaseExpression): field = _get_field(model, name) if isinstance(field, MoneyField): clean_name = _get_clean_name(name) arg.children[i] = Q(*[ child, ('_'.join([clean_name, 'currency']), F(get_currency_field_name(value.name))) ]) return args
def get_value(self, data): """ Test that the returned amount is a valid Decimal """ amount = super(DecimalField, self).get_value(data) # Convert an empty string to None if len(str(amount).strip()) == 0: amount = None try: if amount is not None and amount is not empty: amount = Decimal(amount) except: raise ValidationError({ self.field_name: [_("Must be a valid number")], }) currency = data.get(get_currency_field_name(self.field_name), self.default_currency) if currency and amount is not None and not isinstance( amount, MONEY_CLASSES) and amount is not empty: return Money(amount, currency) return amount
def _expand_money_params(kwargs): def get_clean_name(name): # Get rid of __lt, __gt etc for the currency lookup path = name.split(LOOKUP_SEP) if path[-1] in QUERY_TERMS: return LOOKUP_SEP.join(path[:-1]) else: return name from moneyed import Money try: from django.db.models.constants import LOOKUP_SEP except ImportError: # Django < 1.5 LOOKUP_SEP = '__' from django.db.models.sql.constants import QUERY_TERMS to_append = {} for name, value in kwargs.items(): if isinstance(value, Money): clean_name = get_clean_name(name) to_append[name] = value.amount to_append[get_currency_field_name(clean_name)] = smart_unicode( value.currency) if isinstance(value, BaseExpression): clean_name = get_clean_name(name) to_append['_'.join([clean_name, 'currency' ])] = F('_'.join([value.name, 'currency'])) kwargs.update(to_append) return kwargs
def contribute_to_class(self, cls, name): cls._meta.has_money_field = True # Don't run on abstract classes # Removed, see https://github.com/jakewins/django-money/issues/42 # if cls._meta.abstract: # return if not self.frozen_by_south: c_field_name = get_currency_field_name(name) # Do not change default=self.default_currency.code, needed # for south compat. c_field = CurrencyField( max_length=3, price_field=self, default=self.default_currency, editable=False, choices=self.currency_choices, ) c_field.creation_counter = self.creation_counter cls.add_to_class(c_field_name, c_field) super(MoneyField, self).contribute_to_class(cls, name) setattr(cls, self.name, MoneyFieldProxy(self))
def Deserializer(stream_or_string, **options): """ Deserialize a stream or string of JSON data. """ if not isinstance(stream_or_string, (bytes, six.string_types)): stream_or_string = stream_or_string.read() if isinstance(stream_or_string, bytes): stream_or_string = stream_or_string.decode('utf-8') try: for obj in json.loads(stream_or_string): money_fields = {} fields = {} Model = _get_model(obj["model"]) for (field_name, field_value) in six.iteritems(obj['fields']): field = Model._meta.get_field(field_name) if isinstance(field, MoneyField) and field_value is not None: money_fields[field_name] = Money(field_value, obj['fields'][get_currency_field_name(field_name)]) else: fields[field_name] = field_value obj['fields'] = fields for obj in PythonDeserializer([obj], **options): for field, value in money_fields.items(): setattr(obj.object, field, value) yield obj except GeneratorExit: raise
def value_from_datadict(self, data, files, name): if name not in data: return None amount, currency = data.get(name), data.get(get_currency_field_name(name)) if isinstance(amount, Money): return amount return Money(amount=amount, currency=currency)
def Deserializer(stream_or_string, **options): """ Deserialize a stream or string of JSON data. """ if not isinstance(stream_or_string, (bytes, six.string_types)): stream_or_string = stream_or_string.read() if isinstance(stream_or_string, bytes): stream_or_string = stream_or_string.decode('utf-8') try: for obj in json.loads(stream_or_string): money_fields = {} fields = {} Model = _get_model(obj["model"]) for (field_name, field_value) in six.iteritems(obj['fields']): field = Model._meta.get_field(field_name) if isinstance(field, MoneyField) and field_value is not None: money_fields[field_name] = Money( field_value, obj['fields'][get_currency_field_name(field_name)]) else: fields[field_name] = field_value obj['fields'] = fields for obj in PythonDeserializer([obj], **options): for field, value in money_fields.items(): setattr(obj.object, field, value) yield obj except GeneratorExit: raise
def _expand_money_params(kwargs): def get_clean_name(name): # Get rid of __lt, __gt etc for the currency lookup path = name.split(LOOKUP_SEP) if path[-1] in QUERY_TERMS: return LOOKUP_SEP.join(path[:-1]) else: return name from moneyed import Money try: from django.db.models.constants import LOOKUP_SEP except ImportError: # Django < 1.5 LOOKUP_SEP = '__' from django.db.models.sql.constants import QUERY_TERMS to_append = {} for name, value in kwargs.items(): if isinstance(value, Money): clean_name = get_clean_name(name) to_append[name] = value.amount to_append[get_currency_field_name(clean_name)] = smart_unicode( value.currency) if isinstance(value, ExpressionNode): clean_name = get_clean_name(name) to_append['_'.join([clean_name, 'currency'])] = F('_'.join([value.name, 'currency'])) kwargs.update(to_append) return kwargs
def value_from_datadict(self, data, files, name): if name not in data: return None amount, currency = data.get(name), data.get( get_currency_field_name(name)) if isinstance(amount, Money): return amount return Money(amount=amount, currency=currency)
def get_value(self, data): amount = super().get_value(data) currency = data.get(get_currency_field_name(self.field_name), self.default_currency) if currency and amount is not None and not isinstance( amount, MONEY_CLASSES) and amount is not empty: return Money(amount, currency) return amount
def _expand_money_kwargs(model, kwargs): """ Augments kwargs so that they contain _currency lookups. """ to_append = {} for name, value in kwargs.items(): if isinstance(value, Money): clean_name = _get_clean_name(name) to_append[name] = value.amount to_append[get_currency_field_name(clean_name)] = smart_unicode( value.currency) if isinstance(value, BaseExpression): field = _get_field(model, name) if isinstance(field, MoneyField): clean_name = _get_clean_name(name) to_append['_'.join([clean_name, 'currency'])] = F(get_currency_field_name(value.name)) kwargs.update(to_append) return kwargs
def get_value(self, data): amount = super(MoneyField, self).get_value(data) currency = data.get(get_currency_field_name(self.field_name), None) # prevent circular dependency from rest_framework.fields import empty if currency and amount is not None: if amount == '' or type(amount) == empty: return None return Money(amount, currency) return amount
def render(self, name, value, attrs=None): amount, currency = '', '' if isinstance(value, Money): amount = value.amount currency = value.currency.code if isinstance(value, tuple): amount, currency = value[:2] if isinstance(value, (int, Decimal)): amount = value currency = self.default_currency result = super(InputMoneyWidget, self).render(name, amount, attrs) name = get_currency_field_name(name) attrs['id'] = 'id_' + name result += self.currency_widget.render(name, currency, attrs) return result
def Deserializer(stream_or_string, **options): """ Deserialize a stream or string of JSON data. """ ignore = options.pop('ignorenonexistent', False) if not isinstance(stream_or_string, (bytes, six.string_types)): stream_or_string = stream_or_string.read() if isinstance(stream_or_string, bytes): stream_or_string = stream_or_string.decode('utf-8') try: for obj in json.loads(stream_or_string): money_fields = {} fields = {} try: Model = _get_model(obj["model"]) except DeserializationError: if ignore: continue else: raise try: field_names = set(f.name for f in Model._meta.get_fields()) except AttributeError: field_names = set(f.name for f in Model._meta.fields) for (field_name, field_value) in six.iteritems(obj['fields']): if ignore and field_name not in field_names: # skip fields no longer on model continue field = Model._meta.get_field(field_name) if isinstance(field, MoneyField) and field_value is not None: money_fields[field_name] = Money( field_value, obj['fields'][get_currency_field_name(field_name)]) else: fields[field_name] = field_value obj['fields'] = fields for obj in PythonDeserializer([obj], **options): for field, value in money_fields.items(): setattr(obj.object, field, value) yield obj except GeneratorExit: raise
def Deserializer(stream_or_string, **options): """ Deserialize a stream or string of JSON data. """ ignore = options.pop('ignorenonexistent', False) if not isinstance(stream_or_string, (bytes, six.string_types)): stream_or_string = stream_or_string.read() if isinstance(stream_or_string, bytes): stream_or_string = stream_or_string.decode('utf-8') try: for obj in json.loads(stream_or_string): money_fields = {} fields = {} try: Model = _get_model(obj['model']) except DeserializationError: if ignore: continue else: raise try: field_names = set(f.name for f in Model._meta.get_fields()) except AttributeError: field_names = set(f.name for f in Model._meta.fields) for (field_name, field_value) in six.iteritems(obj['fields']): if ignore and field_name not in field_names: # skip fields no longer on model continue field = Model._meta.get_field(field_name) if isinstance(field, MoneyField) and field_value is not None: money_fields[field_name] = Money(field_value, obj['fields'][get_currency_field_name(field_name)]) else: fields[field_name] = field_value obj['fields'] = fields for inner_obj in PythonDeserializer([obj], **options): for field, value in money_fields.items(): setattr(inner_obj.object, field, value) yield inner_obj except GeneratorExit: raise
def contribute_to_class(self, cls, name): # Don't run on abstract classes if cls._meta.abstract: return if not self.frozen_by_south: c_field_name = get_currency_field_name(name) # Do not change default=self.default_currency.code, needed # for south compat. c_field = CurrencyField( max_length=3, price_field=self, default=self.default_currency, editable=False, choices=self.currency_choices ) c_field.creation_counter = self.creation_counter cls.add_to_class(c_field_name, c_field) super(MoneyField, self).contribute_to_class(cls, name) setattr(cls, self.name, MoneyFieldProxy(self))
def contribute_to_class(self, cls, name): cls._meta.has_money_field = True # Don't run on abstract classes # Removed, see https://github.com/jakewins/django-money/issues/42 # if cls._meta.abstract: # return if not self.frozen_by_south: c_field_name = get_currency_field_name(name) # Do not change default=self.default_currency.code, needed # for south compat. c_field = CurrencyField(max_length=3, price_field=self, default=self.default_currency, editable=False, choices=self.currency_choices) c_field.creation_counter = self.creation_counter cls.add_to_class(c_field_name, c_field) super(MoneyField, self).contribute_to_class(cls, name) setattr(cls, self.name, MoneyFieldProxy(self))
def __init__(self, field): self.field = field self.currency_field_name = get_currency_field_name(self.field.name)
def _check_currency(obj, field, amt): currency_field_name = get_currency_field_name(field.name) if obj.__dict__[currency_field_name] != str(amt.currency): raise ValueError( 'You cannot use F() with different currencies.')
def Deserializer(stream_or_string, **options): # noqa """ Deserialize a stream or string of JSON data. """ # Copied almost without changes from djmoney.serializers (django-money). # Adding support for situation where old models to be deserialized have # price field, but not price_currency field. # In Ralph, price field existed before in various models as # a Decimal field. All price fields were migrated to MoneyField # without changing the original field name. This can cause problems # in original django-money's implementation of Deserializer. # This updated Deserializer is needed to get reversion (django-reversion) # to work in circumstances described above. from django.core.serializers.python import \ Deserializer as PythonDeserializer, _get_model ignore = options.pop("ignorenonexistent", False) if not isinstance(stream_or_string, (bytes, six.string_types)): stream_or_string = stream_or_string.read() if isinstance(stream_or_string, bytes): stream_or_string = stream_or_string.decode("utf-8") try: for obj in json.loads(stream_or_string): try: Model = _get_model(obj["model"]) except DeserializationError: if ignore: continue else: raise money_fields = {} fields = {} field_names = {field.name for field in Model._meta.get_fields()} for (field_name, field_value) in six.iteritems(obj["fields"]): if ignore and field_name not in field_names: # skip fields no longer on model continue field = Model._meta.get_field(field_name) if isinstance(field, MoneyField) and field_value is not None: try: currency = \ obj["fields"][get_currency_field_name(field_name)] except KeyError: currency = DEFAULT_CURRENCY_CODE money_fields[field_name] = Money(field_value, currency) else: fields[field_name] = field_value obj["fields"] = fields for inner_obj in PythonDeserializer([obj], **options): for field, value in money_fields.items(): setattr(inner_obj.object, field, value) yield inner_obj except (GeneratorExit, DeserializationError): raise except Exception as exc: six.reraise( DeserializationError, DeserializationError(exc), sys.exc_info()[2] )
def get_value(self, data): amount = super(MoneyField, self).get_value(data) currency = data.get(get_currency_field_name(self.field_name), None) if currency: return Money(amount, currency) return amount
def field_from_native(self, data, files, field_name, into): super(MoneyField, self).field_from_native(data, files, field_name, into) currency = data.get(get_currency_field_name(field_name), None) if currency: into[field_name] = Money(into[field_name], currency)
def get_value(self, data): amount = super(MoneyField, self).get_value(data) currency = data.get(get_currency_field_name(self.field_name), self.default_currency) if currency and amount is not None and not isinstance(amount, MONEY_CLASSES) and amount is not empty: return Money(amount, currency) return amount