django-elasticsearch-dsl-drf icon indicating copy to clipboard operation
django-elasticsearch-dsl-drf copied to clipboard

Strange behaviour of DictionaryProxy

Open Widly opened this issue 7 years ago • 8 comments

Hi!

I have ES document with date field and corresponding Django model DateTimeField. However, when i'm trying to retrieve document via drf, it returns datetime.date object, not datetime.datetime, how expected. In debug mode i found, that serializer gets field values through DictionaryProxy (utils.py): image Why it should convert datetime.datetime to datetime.date?

Widly avatar Nov 23 '18 12:11 Widly

@Widly:

Thanks for reporting this.

It's indeed an issue, however not an easy one. There's only one date type in Elastic and that's date. It serves both, though.

Would you consider 23:30:59T00:00:00 a date or a datetime? I guess it should be possible to read the stored format (or specify it explicitly for the given field).

Any help here is appreciated.

barseghyanartur avatar Nov 23 '18 23:11 barseghyanartur

Hi, I just found this issue too and the serialization process is not consistent between single and multiple objects. In single objects the field is serialized as a date, but in multiple objects (a list request for example) the field is serialized as a datetime.

I might be wrong, but my guess is that serializing everything as datetime would be better as it does not cut information from dates nor datetimes, however serializing everything as a date cuts some information from datetimes.

piedrahitapablo avatar Mar 15 '19 23:03 piedrahitapablo

I had the same error. I made a patch / hack to add a test if the date has a timezone :

        val = self.__mapping.get(item, None)
        if isinstance(val, datetime.datetime) and not val.tzinfo:
            val = val.date()
        return val

It works but it's not a perfect solution and it might not work in your environement.

yleclanche avatar Mar 18 '21 10:03 yleclanche

For me does not occur on list just retrieve and the first clue to the error i got was

'datetime.date' object has no attribute 'utcoffset'

In my settings.py i monkey patched like so

"""
MONKEY PATCH
"""

from django_elasticsearch_dsl_drf.utils import DictionaryProxy as OrgDictionaryProxy
import django_elasticsearch_dsl_drf.utils
import datetime

class DictionaryProxy(OrgDictionaryProxy):
    """site-packages/django_elasticsearch_dsl_drf/utils.py"""

    def __getattr__(self, item):
        val = self.__mapping.get(item, None)
        if isinstance(val, datetime.datetime) and not val.tzinfo:
            val = val.date()
        return val

django_elasticsearch_dsl_drf.utils.DictionaryProxy = DictionaryProxy

I don't use date objects so i'm not really testing that. Just remember to watch the releases and remove the patch when it gets fixed.

I hope this helps people needing to work around this.

NoelJames avatar Mar 23 '21 18:03 NoelJames

@yleclanche, @NoelJames, @piedrahitapablo:

Thanks for your input. Could you guys, come to a consensus that will be useful for all of you? I'll see then what I can do.

barseghyanartur avatar Mar 23 '21 19:03 barseghyanartur

Some other odd things i noticed was that in retrieve nested objects were not effect by this and, it wasn't an issue in list. IMHO I don't think having this one off behavior is helping anybody.

It would seem that to do this properly you'd need need to know the serializer field it goes into. Perhaps, there would be a better place to change the type?

Want to add that this project is very useful to me. Thank you

NoelJames avatar Mar 24 '21 01:03 NoelJames

  • I've added ... and not val.tzinfo as you suggested.
  • I've added the DictionaryProxy as a property (dictionary_proxy) to the BaseDocumentViewSet so that you wouldn't have to monkey patch.

Further than that, your input is very valuable.

barseghyanartur avatar Mar 24 '21 14:03 barseghyanartur

FYI, improvements mentioned above are released in 0.22. Feel free to add.

barseghyanartur avatar Mar 26 '21 01:03 barseghyanartur