Skip to content

Commit

Permalink
Drop support for Django < 1.8 (#295)
Browse files Browse the repository at this point in the history
* Drop support for Django < 1.8

* Cleanup

* Fix dependency
  • Loading branch information
Stranger6667 committed May 19, 2017
1 parent 3afce1b commit 813c785
Show file tree
Hide file tree
Showing 28 changed files with 114 additions and 680 deletions.
15 changes: 0 additions & 15 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,5 @@ env:
- TOX_ENV=django18-py32
- TOX_ENV=django18-py27
- TOX_ENV=django18-pypy
- TOX_ENV=django17-py34
- TOX_ENV=django17-py33
- TOX_ENV=django17-py32
- TOX_ENV=django17-py27
- TOX_ENV=django17-pypy
- TOX_ENV=django16-py33
- TOX_ENV=django16-py32
- TOX_ENV=django16-py27
- TOX_ENV=django16-pypy
- TOX_ENV=django15-py27
- TOX_ENV=django15-py33
- TOX_ENV=django15-py32
- TOX_ENV=django15-pypy
- TOX_ENV=django14-py27
- TOX_ENV=django14-pypy
after_success:
- codecov
38 changes: 3 additions & 35 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ http://code.google.com/p/python-money/

This version adds tests, and comes with several critical bugfixes.

Django versions supported: 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 1.10, 1.11
Django versions supported: 1.8, 1.9, 1.10, 1.11

Python versions supported: 2.7, 3.2, 3.3, 3.4, 3.5, 3.6

Expand Down Expand Up @@ -102,10 +102,6 @@ instead.
balance = MoneyField(max_digits=10, decimal_places=2, validators=[MinValueValidator(MoneyPatched(100, 'GBP'))])
If you use South to handle model migration, things will "Just Work" out
of the box. South is an optional dependency and things will work fine
without it.

Adding a new Currency
---------------------

Expand Down Expand Up @@ -258,23 +254,6 @@ Formatting the number with currency:

MoneyPatched object

Admin integration
-----------------

For Django **1.7+** integration works automatically if ``djmoney`` is in the ``INSTALLED_APPS``.

For older versions you should use the following code:

.. code:: python
from djmoney.admin import setup_admin_integration
# NOTE. Only for Django < 1.7
setup_admin_integration()
There is no single opinion about where to place on-start-up code in Django < 1.7, but we'd recommend to place it
in the top-level `urls.py`.

Testing
-------
Expand Down Expand Up @@ -319,19 +298,8 @@ conversions happening in different directions.
Usage with Django REST Framework
--------------------------------

In Django **1.7+**, for MoneyFields to automatically work with Django REST Framework, make sure
that ``djmoney`` is in the ``INSTALLED_APPS`` of your ``settings.py``.

For older versions you should use the following code:

.. code:: python
from djmoney.contrib.django_rest_framework import register_money_field
# NOTE. Only for Django < 1.7
register_money_field()
Just put it in the end of your root ``urls.py`` file.
Make sure that ``djmoney`` is in the ``INSTALLED_APPS`` of your ``settings.py`` and MoneyFields to automatically
work with Django REST Framework.

Built-in serializer works in the following way:

Expand Down
99 changes: 0 additions & 99 deletions djmoney/_compat.py
Original file line number Diff line number Diff line change
@@ -1,57 +1,15 @@
# -*- coding: utf-8 -*-
# flake8: noqa
import functools

from django import VERSION
from django.db.models.manager import ManagerDescriptor


try:
import django.contrib.admin.utils as admin_utils
except ImportError:
# Django < 1.5
import django.contrib.admin.util as admin_utils

try:
from django.db.models.constants import LOOKUP_SEP
except ImportError:
# Django < 1.5
LOOKUP_SEP = '__'

try:
from django.db.models.expressions import BaseExpression
except ImportError:
# Django < 1.8
from django.db.models.expressions import ExpressionNode as BaseExpression

try:
from django.contrib.admin.utils import lookup_field
except ImportError:
from django.contrib.admin.util import lookup_field

try:
from django.utils.encoding import smart_unicode
except ImportError:
# Python 3
from django.utils.encoding import smart_text as smart_unicode

try:
from django.db.models import Case, Func, Value, When
except ImportError:
Case, Func, Value, When = None, None, None, None

try:
from django.utils.six import wraps
except ImportError:
# Django 1.5, and some versions from 1.4.x branch
def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, updated=functools.WRAPPER_UPDATES):

def wrapper(f):
f = functools.wraps(wrapped)(f)
f.__wrapped__ = wrapped
return f

return wrapper

try:
string_types = (basestring,)
Expand All @@ -71,63 +29,6 @@ def wrapper(f):
# Python 3.2 & 3.3
from imp import reload as reload_module

if VERSION >= (1, 7):
from django.utils.deconstruct import deconstructible
else:
def deconstructible(cls):
return cls


def split_expression(expr):
"""
Returns lhs and rhs of the expression.
"""
if VERSION < (1, 8):
return expr.children
else:
return expr.lhs, expr.rhs


def set_expression_rhs(expr, value):
"""
Sets right hand side value of the expression.
"""
if VERSION < (1, 8):
expr.children[1] = value
else:
expr.rhs.value = value


def get_field_names(model):
"""
Returns a set of field names associated with the model.
"""
opts = model._meta
if VERSION < (1, 8):
return opts.get_all_field_names()
else:
return {field.name for field in opts.get_fields()}


def get_fields(model):
"""
Returns a set of field instances associated with the model.
"""
opts = model._meta
if VERSION < (1, 8):
return opts.fields
else:
return opts.get_fields()


def resolve_field(qs, parts, opts, alias):
if VERSION < (1, 6):
return qs.setup_joins(parts, opts, alias, False)[0]
elif VERSION[:2] == (1, 6):
return qs.names_to_path(parts, opts, True, True)[1]
else:
return qs.names_to_path(parts, opts, True, fail_on_missing=False)[1]


def setup_managers(sender):
from .models.managers import money_manager
Expand Down
21 changes: 6 additions & 15 deletions djmoney/admin.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,16 @@
# coding: utf-8
from django import VERSION
import django.contrib.admin.utils as admin_utils

from ._compat import admin_utils, text_type
from ._compat import text_type
from .models.fields import MoneyField


def setup_admin_integration():
original_display_for_field = admin_utils.display_for_field

if VERSION < (1, 7):

def display_for_field(value, field):
if isinstance(field, MoneyField):
return text_type(value)
return original_display_for_field(value, field)

else:

def display_for_field(value, field, empty):
if isinstance(field, MoneyField):
return text_type(value)
return original_display_for_field(value, field, empty)
def display_for_field(value, field, empty):
if isinstance(field, MoneyField):
return text_type(value)
return original_display_for_field(value, field, empty)

admin_utils.display_for_field = display_for_field
1 change: 0 additions & 1 deletion djmoney/contrib/django_rest_framework/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
# -*- coding: utf-8 -*-
from .fields import MoneyField, register_money_field # noqa
from .helpers import VERSION # noqa
55 changes: 14 additions & 41 deletions djmoney/contrib/django_rest_framework/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,56 +5,29 @@
from djmoney.utils import get_currency_field_name
from moneyed import Money

from .helpers import IS_DRF_3


class MoneyField(DecimalField):
"""
Treats ``Money`` objects as decimal values in representation and
does decimal's validation during transformation to native value.
"""

if IS_DRF_3: # noqa

def to_representation(self, obj):
return super(MoneyField, self).to_representation(obj.amount)

def to_internal_value(self, data):
if isinstance(data, Money):
amount = super(MoneyField, self).to_internal_value(data.amount)
return Money(amount, data.currency)
return super(MoneyField, self).to_internal_value(data)

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

else:

def to_native(self, value):
amount = value.amount if isinstance(value, Money) else value
return super(MoneyField, self).to_native(amount)

def from_native(self, value):
if isinstance(value, Money):
amount = super(MoneyField, self).from_native(value.amount)
return Money(amount, value.currency)
return super(MoneyField, self).from_native(value)
def to_representation(self, obj):
return super(MoneyField, self).to_representation(obj.amount)

def validate(self, value):
amount = value.amount if isinstance(value, Money) else value
return super(MoneyField, self).validate(amount)
def to_internal_value(self, data):
if isinstance(data, Money):
amount = super(MoneyField, self).to_internal_value(data.amount)
return Money(amount, data.currency)
return super(MoneyField, self).to_internal_value(data)

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), None)
if currency:
return Money(amount, currency)
return amount


def register_money_field():
mapping = ModelSerializer.serializer_field_mapping if IS_DRF_3 else ModelSerializer.field_mapping
mapping[ModelField] = MoneyField
ModelSerializer.serializer_field_mapping[ModelField] = MoneyField
7 changes: 0 additions & 7 deletions djmoney/contrib/django_rest_framework/helpers.py

This file was deleted.

15 changes: 1 addition & 14 deletions djmoney/forms/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@

from warnings import warn

from django import VERSION
from django.core import validators
from django.core.exceptions import ValidationError
from django.forms import ChoiceField, DecimalField, MultiValueField

Expand All @@ -19,10 +17,6 @@

class MoneyField(MultiValueField):

# Django 1.5 compat:
if not hasattr(MultiValueField, 'empty_values'):
empty_values = list(validators.EMPTY_VALUES)

def __init__(self, currency_widget=None, currency_choices=CURRENCY_CHOICES,
choices=CURRENCY_CHOICES, max_value=None, min_value=None,
max_digits=None, decimal_places=None, default_amount=None,
Expand All @@ -42,10 +36,6 @@ def __init__(self, currency_widget=None, currency_choices=CURRENCY_CHOICES,
amount_field = DecimalField(max_value, min_value, max_digits, decimal_places, *args, **kwargs)
currency_field = ChoiceField(choices=choices)

if VERSION < (1, 8) and hasattr(amount_field, '_has_changed') and hasattr(currency_field, '_has_changed'):
amount_field.has_changed = amount_field._has_changed
currency_field.has_changed = currency_field._has_changed

# TODO: No idea what currency_widget is supposed to do since it doesn't
# even receive currency choices as input. Somehow it's supposed to be
# instantiated from outside. Hard to tell.
Expand Down Expand Up @@ -75,7 +65,7 @@ def compress(self, data_list):

def has_changed(self, initial, data): # noqa
if initial is None:
initial = ['' for x in range(0, len(data))]
initial = ['' for _ in range(0, len(data))]
else:
if not isinstance(initial, list):
initial = self.widget.decompress(initial)
Expand Down Expand Up @@ -116,6 +106,3 @@ def has_changed(self, initial, data): # noqa
return True

return False

if VERSION < (1, 8):
_has_changed = has_changed

0 comments on commit 813c785

Please sign in to comment.