wonderbeyond
2/8/2017 - 6:52 AM

mongoengine fields

mongoengine fields

# coding=utf-8
import six
import mongoengine as mng
import datetime
import pytz


class AutoDateTimeField(mng.DateTimeField):
    '''Auto transform to datetime(from raw datetime string)'''
    DEFAULT_FORMAT = "%Y-%m-%d %H:%M:%S"

    def __init__(self, *args, **kwargs):
        self.format = kwargs.pop('format', self.DEFAULT_FORMAT)
        self.store_type = kwargs.pop('store_type', datetime.datetime)
        super(AutoDateTimeField, self).__init__(*args, **kwargs)

    def to_datetime(self, value, **kwargs):
        if isinstance(value, six.string_types):
            return datetime.datetime.strptime(value, self.format)
        return value

    def to_mongo(self, value, **kwargs):
        '''for storage or lookup from storage'''
        value = self.to_datetime(value, **kwargs)
        if self.store_type is datetime.datetime:
            return value
        return value.strftime(self.format)

    def to_python(self, value):
        '''string and datetime types are all allowed in storage'''
        if value is None or isinstance(value, datetime.datetime):
            return value

        return datetime.datetime.strptime(value, self.format)


class AwareDateTimeField(AutoDateTimeField):
    def __init__(self, *args, **kwargs):
        self.timezone = pytz.timezone(kwargs.pop('timezone', 'Asia/Shanghai'))
        super(AwareDateTimeField, self).__init__(*args, **kwargs)

    def to_datetime(self, value, **kwargs):
        value = AutoDateTimeField.to_datetime(self, value, **kwargs)
        if value.tzinfo:
            return value.astimezone(pytz.utc)
        else:   # supposed to be naive local time
            return self.timezone.localize(value).astimezone(pytz.utc)

    def to_mongo(self, value, **kwargs):
        return self.to_datetime(value, **kwargs)

    def to_python(self, value):
        value = AutoDateTimeField.to_python(self, value)
        if value.tzinfo:
            return value.astimezone(self.timezone)
        else:
            return self.timezone.localize(value)

    # for motorengine
    to_son = to_mongo
    from_son = to_python


class RectifiableField(mng.base.BaseField):
    def __init__(self, *args, **kwargs):
        self.corrections = kwargs.pop('corrections')
        self.db_field_type = kwargs.pop('db_field_type')
        self.canonical_field_type = kwargs.pop('canonical_field_type')
        super(RectifiableField, self).__init__(*args, **kwargs)

    def to_python(self, value):
        return self.corrections.get(value)

    def to_mongo(self, value, **kwargs):
        for k, v in self.corrections.items():
            print value, v, k
            print type(value), type(v), type(k)
            if value == v:
                return k
        return value

    def prepare_query_value(self, op, value):
        return self.to_mongo(value)