Django-rest-framework: ์•ฝ๊ฐ„ ๋‹ค๋ฅธ ๋‘ ๊ฐœ์˜ ISO 8601 ๋‚ ์งœ / ์‹œ๊ฐ„ ์ง๋ ฌํ™”

์— ๋งŒ๋“  2016๋…„ 07์›” 11์ผ  ยท  3์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: encode/django-rest-framework

์ฒดํฌ๋ฆฌ์ŠคํŠธ

  • [x]์ด ๋ฌธ์ œ๊ฐ€ Django REST ํ”„๋ ˆ์ž„ ์›Œํฌ์˜ master ๋ธŒ๋žœ์น˜์— ๋Œ€ํ•ด ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค.
  • [x] ์—ด๋ฆฐ ํ‹ฐ์ผ“๊ณผ ๋‹ซํžŒ ํ‹ฐ์ผ“ ๋ชจ๋‘์—์„œ ์œ ์‚ฌํ•œ ๋ฌธ์ œ๋ฅผ ๊ฒ€์ƒ‰ํ–ˆ๋Š”๋ฐ ์ค‘๋ณต ๋œ ํ‹ฐ์ผ“์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  • [x] ์ด๊ฒƒ์€ ์‚ฌ์šฉ๋ฒ• ์งˆ๋ฌธ์ด ์•„๋‹™๋‹ˆ๋‹ค. (๋Œ€์‹  ํ† ๋ก  ๊ทธ๋ฃน์œผ๋กœ ์ „๋‹ฌ ๋˜์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.)
  • [x] ํƒ€์‚ฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ์ทจ๊ธ‰ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. (๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์ด ํƒ€์‚ฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ํ˜•ํƒœ ๋กœ
  • [x] ๊ฐ€๋Šฅํ•œ ๊ฐ€์žฅ ๊ฐ„๋‹จํ•œ ๊ฒฝ์šฐ๋กœ ๋ฌธ์ œ๋ฅผ ์ค„์˜€์Šต๋‹ˆ๋‹ค.
  • [] ํ’€ ์š”์ฒญ์œผ๋กœ ์‹คํŒจํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ํฌํ•จํ–ˆ์Šต๋‹ˆ๋‹ค. (ํ•  ์ˆ˜์—†๋Š” ๊ฒฝ์šฐ์—๋„ ๋ฌธ์ œ๋ฅผ ์ˆ˜๋ฝ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.)

    ์žฌํ˜„ ๋‹จ๊ณ„

ISO-8601 ํ˜•์‹์˜ ๋‚ ์งœ / ์‹œ๊ฐ„ ์ง๋ ฌํ™” ๊ตฌํ˜„์€ ์ฝ”๋“œ๋ฒ ์ด์Šค์—์„œ ์ผ๊ด€๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/fields.py#L1094 ๋งˆ์ดํฌ๋กœ ์ดˆ๋Š” ์ง๋ ฌํ™” ๋œ ๊ฐ’์— ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.
https://github.com/tomchristie/django-rest-framework/blob/master/rest_framework/utils/encoders.py#L30 ์—์„œ๋Š” ๋ฐ€๋ฆฌ ์ดˆ ๋งŒ

์˜ˆ์ƒ๋˜๋Š” ํ–‰๋™

์ผ๊ด€๋œ ๊ตฌํ˜„์„ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค.

์‹ค์ œ ํ–‰๋™

ํ•ด๋‹น ์—†์Œ

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

@georgejlee ์‚ฌ์šฉ์ž ์ง€์ • ๋ Œ๋”๋Ÿฌ๋ฅผ ์‚ฌ์šฉ

import datetime

from rest_framework.renderers import JSONRenderer
from rest_framework.utils.encoders import JSONEncoder

class MilliSecondEncoder(JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime.datetime):
            representation = obj.isoformat()
            if obj.microsecond:
                representation = representation[:23] + representation[26:]
            if representation.endswith('+00:00'):
                representation = representation[:-6] + 'Z'
            return representation
        else:
            return super().default(obj)


class JSONRenderer(JSONRenderer):
    encoder_class = MilliSecondEncoder

ํ , DEFAULT_RENDERER_CLASSES๋ฅผ ์ปค์Šคํ…€ ๋ Œ๋”๋Ÿฌ๋กœ ๋ณ€๊ฒฝํ•ด๋„ ๋ทฐ์…‹์˜ ๋ Œ๋”๋ง์— ์˜ํ–ฅ์„์ฃผ์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. renderer_class๋ฅผ ๋ช…์‹œ ์ ์œผ๋กœ ์„ค์ •ํ•ด์•ผํ–ˆ์Šต๋‹ˆ๋‹ค.

๋ชจ๋“  3 ๋Œ“๊ธ€

ํ˜„์žฌ ๋‚ด API์˜ ์ผ๋ถ€ ํด๋ผ์ด์–ธํŠธ์—๋Š” ๋ฐ€๋ฆฌ ์ดˆ ์ •๋ฐ€๋„์˜ ๋‚ ์งœ๊ฐ€ ํ•„์š”ํ•˜๋ฉฐ ๋งˆ์ดํฌ๋กœ ์ดˆ๋ฅผ ์ฒ˜๋ฆฌ ํ•  ์ˆ˜ โ€‹โ€‹์—†์Šต๋‹ˆ๋‹ค. DRF 3.3 ์„ค์ •์—์„œ 'DATETIME_FORMAT'์„ None์œผ๋กœ ์„ค์ •ํ•˜์—ฌ์ด๋ฅผ ๋‹ฌ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค. 3.4๋กœ ์—…๊ทธ๋ ˆ์ด๋“œํ•˜๋ฉด์ด ๋™์ž‘์ด ์ค‘๋‹จ๋ฉ๋‹ˆ๋‹ค. ์ด์ „ ๋™์ž‘์„ ์‰ฝ๊ฒŒ ์–ป์„ ์ˆ˜์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๊นŒ? ECMA-262 ํ˜•์‹์„ ์ œ๊ณตํ•˜๋Š” datetime ํ˜•์‹ ๋ฌธ์ž์—ด์„ ์ง€์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋‚ผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ฐ์‚ฌ.

@georgejlee ์‚ฌ์šฉ์ž ์ง€์ • ๋ Œ๋”๋Ÿฌ๋ฅผ ์‚ฌ์šฉ

import datetime

from rest_framework.renderers import JSONRenderer
from rest_framework.utils.encoders import JSONEncoder

class MilliSecondEncoder(JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime.datetime):
            representation = obj.isoformat()
            if obj.microsecond:
                representation = representation[:23] + representation[26:]
            if representation.endswith('+00:00'):
                representation = representation[:-6] + 'Z'
            return representation
        else:
            return super().default(obj)


class JSONRenderer(JSONRenderer):
    encoder_class = MilliSecondEncoder

ํ , DEFAULT_RENDERER_CLASSES๋ฅผ ์ปค์Šคํ…€ ๋ Œ๋”๋Ÿฌ๋กœ ๋ณ€๊ฒฝํ•ด๋„ ๋ทฐ์…‹์˜ ๋ Œ๋”๋ง์— ์˜ํ–ฅ์„์ฃผ์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. renderer_class๋ฅผ ๋ช…์‹œ ์ ์œผ๋กœ ์„ค์ •ํ•ด์•ผํ–ˆ์Šต๋‹ˆ๋‹ค.

encoder_class ๋Œ€ํ•ด datetime encoder_class ๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž ์ง€์ • ์ธ์ฝ”๋”๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก DRF๋ฅผ ๊ตฌ์„ฑํ•˜๋ ค๊ณ  ์‹œ๋„ํ•˜๋Š” ๋™์•ˆ ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด์ด ๋ฌธ์ œ๋ฅผ ๋ฐœ๊ฒฌํ•˜๋Š” ๊ฒฝ์šฐ. https://github.com/encode/django-rest-framework/issues/4255#issuecomment -234560555์˜ ์†”๋ฃจ์…˜์ด ๋‚˜๋ฅผ ์œ„ํ•ด ์ผํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ํ•œ ๋ฌธ์ œ๋Š” DRF๊ฐ€ ํ•„๋“œ์˜ DateTimeField ์•„๋‹Œ ํ•œ ๋‚ด์žฅ ์ธ์ฝ”๋”๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. format kwarg๊ฐ€ None ์„ค์ •๋˜์–ด ์žˆ๊ฑฐ๋‚˜ DateTimeField serializer๋ฅผ ์ง€์ •ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ REST_FRAMEWORK ์˜ ๊ตฌ์„ฑ์„ ์„ค์ •ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. DEFAULT_FORMAT: None ์—์„œ settings.py ๊ทธ๋ž˜์•ผ๋งŒ custom encoder ๊ฐ€ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

๊ทธ ์ด์œ ๋Š” ์‚ฌ์šฉ์ž ์ •์˜ Renderer ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ datetime ๋ฅผ ๋ Œ๋”๋ง ํ•˜๊ธฐ ์ „์— serializer ํ•„๋“œ (๋˜๋Š” ๊ธฐ๋ณธ ํ•„๋“œ ๋ Œ๋”๋Ÿฌ)๊ฐ€ Response ํ˜•์‹์„ ์ง€์ •ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ datetime ํ•„๋“œ๋Š” ์ด๋ฏธ ๋ฌธ์ž์—ด์ด๊ณ  ๊ธฐ๋ณธ Python ์œ ํ˜•์ด ์ธ์ฝ”๋”์— ์˜ํ•ด ์ฒ˜๋ฆฌ๋˜๋ฏ€๋กœ ์‚ฌ์šฉ์ž ์ง€์ • ์ธ์ฝ”๋”์˜ default ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ ๊ธฐ๋ณธ JSONEncoder๊ฐ€ ์‚ฌ์šฉ์ž ์ง€์ • ์ธ์ฝ”๋”๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰