Alpine の Docker 環境で、Django Cartridge のテストに失敗していた
File "/var/src/venv/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 958, in prepare_value
value = field.get_db_prep_save(value, connection=self.connection)
File "/var/src/venv/lib/python3.6/site-packages/django/db/models/fields/__init__.py", line 1612, in get_db_prep_save
self.max_digits, self.decimal_places)
File "/var/src/venv/lib/python3.6/site-packages/django/db/backends/base/operations.py", line 493, in adapt_decimalfield_value
return utils.format_number(value, max_digits, decimal_places)
File "/var/src/venv/lib/python3.6/site-packages/django/db/backends/utils.py", line 200, in format_number
value = value.quantize(decimal.Decimal(".1") ** decimal_places, context=context)
decimal.InvalidOperation: [<class 'decimal.InvalidOperation'>]
InvalidOperation: [<class 'decimal.InvalidOperation'>]
が出ていた。
調査すると
decimal_places が 127 になってた。
(別のテスト環境だと0で、テストが成功していた)
decimal_places は、
./manage.py shell
from locale import localeconv; localeconv()
{'currency_symbol': '¥',
'decimal_point': '.',
'frac_digits': 0,
'grouping': [],
'int_curr_symbol': 'JPY ',
'int_frac_digits': 0,
'mon_decimal_point': '.',
'mon_grouping': [3, 3, 0],
'mon_thousands_sep': ',',
'n_cs_precedes': 1,
'n_sep_by_space': 0,
'n_sign_posn': 4,
'negative_sign': '-',
'p_cs_precedes': 1,
'p_sep_by_space': 0,
'p_sign_posn': 1,
'positive_sign': '',
'thousands_sep': ''}
この、frac_digits が使われる。
テストが失敗する環境だと
{'currency_symbol': '',
'decimal_point': '.',
'frac_digits': 127,
'grouping': [],
'int_curr_symbol': '',
'int_frac_digits': 127,
'mon_decimal_point': '',
'mon_grouping': [],
'mon_thousands_sep': '',
'n_cs_precedes': 127,
'n_sep_by_space': 127,
'n_sign_posn': 127,
'negative_sign': '',
'p_cs_precedes': 127,
'p_sep_by_space': 127,
'p_sign_posn': 127,
'positive_sign': '',
'thousands_sep': ''}
となっている。ロケールが足りないっぽい。
Dockerfile をこのように書いて、ロケール musl-locales を作ってみたが
ENV MUSL_LOCPATH="/usr/share/i18n/locales/musl"
RUN apk --no-cache add libintl && \
apk --no-cache --virtual .locale_build add cmake make musl-dev gcc gettext-dev git && \
git clone https://gitlab.com/ytyng/musl-locales && \
cd musl-locales && cmake -DLOCALE_PROFILE=OFF -DCMAKE_INSTALL_PREFIX:PATH=/usr . && make && make install && \
cd .. && rm -r musl-locales && \
apk del .locale_build
それでも int_frac_digits は変更されなかった。
方法がわからなかったので、
django の settings で
setattr(locale, '_override_localeconv',
{'currency_symbol': '¥',
'decimal_point': '.',
'frac_digits': 0,
'grouping': [],
'int_curr_symbol': 'JPY ',
'int_frac_digits': 0,
'mon_decimal_point': '.',
'mon_grouping': [3, 3, 0],
'mon_thousands_sep': ',',
'n_cs_precedes': 1,
'n_sep_by_space': 0,
'n_sign_posn': 4,
'negative_sign': '-',
'p_cs_precedes': 1,
'p_sep_by_space': 0,
'p_sign_posn': 1,
'positive_sign': '',
'thousands_sep': ''})
こんな感じで、locale._override_localeconv をパッチすると、テストが通るようになった。
ロケールが絡む環境では、Alpine Linux より Debian などを使ったほうがいいかもしれない。
コメント